package com.crm.business.crm.service.impl;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.crm.business.admin.service.AdminFileService;
import com.crm.business.admin.service.AdminService;
import com.crm.business.admin.service.IAdminDeptService;
import com.crm.business.crm.mapper.CrmContractMapper;
import com.crm.business.crm.mapper.CrmReceivablesPlanMapper;
import com.crm.business.crm.service.*;
import com.crm.business.examine.service.ExamineService;
import com.crm.business.servlet.BaseServiceImpl;
import com.crm.business.utils.ActionRecordUtil;
import com.crm.business.utils.AuthUtil;
import com.crm.business.utils.BiTimeUtil;
import com.crm.business.utils.UserCacheUtil;
import com.crm.business.utils.UserUtil;
import com.crm.common.constant.Constants;
import com.crm.common.core.redis.RedisCache;
import com.crm.common.crm.common.CrmModel;
import com.crm.common.crm.common.ElasticUtil;
import com.crm.common.crm.constant.*;
import com.crm.common.crm.entity.BO.*;
import com.crm.common.crm.entity.PO.*;
import com.crm.common.crm.entity.VO.CrmFieldSortVO;
import com.crm.common.crm.entity.VO.CrmInfoNumVO;
import com.crm.common.crm.entity.VO.CrmMembersSelectVO;
import com.crm.common.crm.entity.VO.CrmModelFiledVO;
import com.crm.common.ka.core.common.Const;
import com.crm.common.ka.core.common.SystemCodeEnum;
import com.crm.common.ka.core.common.log.BehaviorEnum;
import com.crm.common.ka.core.entity.BasePage;
import com.crm.common.ka.core.entity.UserInfo;
import com.crm.common.ka.core.exception.CrmException;
import com.crm.common.ka.core.feign.admin.entity.AdminConfigBo;
import com.crm.common.ka.core.feign.admin.entity.AdminMessageEnum;
import com.crm.common.ka.core.feign.admin.entity.SimpleUser;
import com.crm.common.ka.core.feign.crm.entity.BiParams;
import com.crm.common.ka.core.feign.crm.entity.CrmEventBO;
import com.crm.common.ka.core.feign.crm.entity.QueryEventCrmPageBO;
import com.crm.common.ka.core.feign.crm.entity.SimpleCrmEntity;
import com.crm.common.ka.core.feign.examine.entity.ExamineRecordReturnVO;
import com.crm.common.ka.core.feign.examine.entity.ExamineRecordSaveBO;
import com.crm.common.ka.core.servlet.upload.FileEntity;
import com.crm.common.ka.core.utils.TagUtil;
import com.crm.common.utils.DateUtils;
import com.crm.common.utils.DesensitizedUtils;
import com.crm.common.utils.StringUtils;
import com.crm.common.utils.bean.BeanExtendUtils;
import com.crm.common.utils.spring.SpringUtils;

import org.apache.ibatis.annotations.Param;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.sum.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 合同表 服务实现类
 * </p>
 *
 * @author zhangzhiwei
 * @since 2020-05-27
 */
@Service
@Slf4j
public class CrmContractServiceImpl extends BaseServiceImpl<CrmContractMapper, CrmContract> implements ICrmContractService, CrmPageService {

    @Autowired
    private ICrmFieldService crmFieldService;

    @Autowired
    private ICrmContractDataService crmContractDataService;

    @Autowired
    private ICrmExamineService crmExamineService;

    @Autowired
    private ICrmExamineLogService examineLogService;

    @Autowired
    private ICrmExamineRecordService examineRecordService;

    @Autowired
    private AdminService adminService;

    @Autowired
    private ICrmNumberSettingService crmNumberSettingService;

    @Autowired
    private ICrmActionRecordService crmActionRecordService;

    @Autowired
    private ICrmActivityService crmActivityService;

    @Autowired
    private ICrmBackLogDealService crmBackLogDealService;

    @Autowired
    private ICrmContractProductService crmContractProductService;

    @Autowired
    private ICrmBusinessProductService crmBusinessProductService;

    @Autowired
    private ICrmReceivablesPlanService crmReceivablesPlanService;

    @Autowired
    private ICrmCustomerService crmCustomerService;

    @Autowired
    private ActionRecordUtil actionRecordUtil;

    @Autowired
    private AdminFileService adminFileService;

    @Autowired
    private ICrmReceivablesService crmReceivablesService;

    @Autowired
    private ExamineService examineService;

    @Autowired
    private ICrmStudentService crmStudentService;
    @Autowired
    private BillCrmOrderPoolService crmOrderPoolService;
    @Autowired
    private IBillCrmStudentPoolService crmStudentPoolService;
    @Value("${crmOrder.expireTimeNum}")
    private Integer expireTimeNum;
    @Autowired
    private ICrmLeadsService crmLeadsService;
    @Autowired
    private RedisCache redisCache;


    /**
     * 大的搜索框的搜索字段
     *
     * @return fields
     */
    @Override
    public String[] appendSearch() {
        return new String[]{"name", "num", "customerName", "studentName", "phone"};
    }

    /**
     * 获取crm列表类型
     *
     * @return data
     */
    @Override
    public CrmEnum getLabel() {
        return CrmEnum.CONTRACT;
    }

    /**
     * 查询所有字段
     *
     * @return data
     */
    @Override
    public List<CrmModelFiledVO> queryDefaultField() {
        List<CrmModelFiledVO> filedList = crmFieldService.queryField(getLabel().getType());
        filedList.add(new CrmModelFiledVO("lastTime", FieldEnum.DATETIME, 1));
        filedList.add(new CrmModelFiledVO("updateTime", FieldEnum.DATETIME, 1));
        filedList.add(new CrmModelFiledVO("createTime", FieldEnum.DATETIME, 1));
        filedList.add(new CrmModelFiledVO("roUserId", FieldEnum.CHECKBOX, 1));
        filedList.add(new CrmModelFiledVO("rwUserId", FieldEnum.CHECKBOX, 1));
        filedList.add(new CrmModelFiledVO("ownerUserId", FieldEnum.USER, 1));
        filedList.add(new CrmModelFiledVO("createUserId", FieldEnum.USER, 1));
        filedList.add(new CrmModelFiledVO("companyUserId", FieldEnum.USER, 1));
        filedList.add(new CrmModelFiledVO("checkStatus", FieldEnum.TEXT, 1));
        filedList.add(new CrmModelFiledVO("contractId", FieldEnum.TEXT, 1));
        filedList.add(new CrmModelFiledVO("receivedMoney", FieldEnum.TEXT, 1));
        filedList.add(new CrmModelFiledVO("unreceivedMoney", FieldEnum.TEXT, 1));
        return filedList;
    }

    /**
     * 查询字段配置
     *
     * @param id 主键ID
     * @return data
     */
    @Override
    public List<CrmModelFiledVO> queryField(Integer id) {
        CrmModel crmModel = queryById(id);
        if (id != null) {
            List<JSONObject> customerList = new ArrayList<>();
            if (crmModel.get("customerId") != null) {
                JSONObject customer = new JSONObject();
                customerList.add(customer.fluentPut("customerId", crmModel.get("customerId")).fluentPut("customerName", crmModel.get("customerName")));
            }
            crmModel.put("customerId", customerList);
            if (crmModel.get("businessId") != null) {
                crmModel.put("businessId", Collections.singletonList(new JSONObject().fluentPut("businessId", crmModel.get("businessId")).fluentPut("businessName", crmModel.get("businessName"))));
            } else {
                crmModel.put("businessId", new ArrayList<>());
            }
            if (crmModel.get("contactsId") != null) {
                crmModel.put("contactsId", Collections.singletonList(new JSONObject().fluentPut("contactsId", crmModel.get("contactsId")).fluentPut("name", crmModel.get("contactsName"))));
            } else {
                crmModel.put("contactsId", new ArrayList<>());
            }
        }
        List<CrmModelFiledVO> vos = crmFieldService.queryField(crmModel);

        CrmModelFiledVO contractCategory = vos.stream().filter(item -> "contractCategory".equals(item.getFieldName())).collect(Collectors.toList()).get(0);
        List<String> categoryOptions = new ArrayList<>(Arrays.asList(contractCategory.getOptions().split(Const.SEPARATOR)));
        categoryOptions.removeIf(CrmBusinessConstEnum.账单类别_账单合同.getMsg()::equals);
        String newOptions = String.join(Const.SEPARATOR, categoryOptions);
        contractCategory.setOptions(newOptions);
        contractCategory.getSetting().removeIf(CrmBusinessConstEnum.账单类别_账单合同.getMsg()::equals);

        vos.removeIf(field -> field.getFieldName().equals("contractCategory"));
        vos.add(contractCategory.getSorting(),contractCategory);


        // 产品
//        JSONObject object = new JSONObject();
//        object.fluentPut("discountRate", crmModel.get("discountRate")).fluentPut("product", crmContractProductService.queryList(id)).fluentPut("totalPrice", crmModel.get("totalPrice"));
//        vos.add(new CrmModelFiledVO().setFieldName("product").setName("产品").setValue(object).setFormType("product").setSetting(new ArrayList<>()).setIsNull(0).setFieldType(1));

        //合同编号 不在新增 编辑页面 显示
        vos.removeIf(field -> field.getFieldName().equals("num"));

        //整单折扣,下单日期,货币名称,已回款金额,未回款金额,回款状态,应回款金额,最近回款时间,退款金额,已开票金额,退款状态,未开票金额  客户来源 不在新增修改页面显示
        vos.removeIf(field -> field.getFieldName().equals("discountRate"));
        vos.removeIf(field -> field.getFieldName().equals("orderDate"));
        vos.removeIf(field -> field.getFieldName().equals("currencyName"));
        vos.removeIf(field -> field.getFieldName().equals("receivedMoney"));
        vos.removeIf(field -> field.getFieldName().equals("unreceivedMoney"));
        vos.removeIf(field -> field.getFieldName().equals("backStatus"));
        vos.removeIf(field -> field.getFieldName().equals("dueMonery"));
        vos.removeIf(field -> field.getFieldName().equals("recentBackTime"));
        vos.removeIf(field -> field.getFieldName().equals("refundMonery"));
        vos.removeIf(field -> field.getFieldName().equals("invoicedMonery"));
        vos.removeIf(field -> field.getFieldName().equals("uninvoicedMonery"));
        vos.removeIf(field -> field.getFieldName().equals("source"));
        vos.removeIf(field -> field.getFieldName().equals("dealStatus"));
        vos.removeIf(field -> field.getFieldName().equals("dealTime"));

        vos.removeIf(field -> field.getFieldName().equals("isRepetition"));

//        vos.removeIf(field -> field.getFieldName().equals("returnType") && CrmEnum.CONTRACT.getType().equals(crmModel.getLabel()));
        vos.removeIf(field -> field.getFieldName().equals("overdueStatus"));
        vos.removeIf(field -> field.getFieldName().equals("ownerOrderPool"));
        vos.removeIf(field -> field.getFieldName().equals("repaymentStatus"));
        vos.removeIf(field -> field.getFieldName().equals("dropOutMoney"));
        vos.removeIf(field -> field.getFieldName().equals("repairMoney"));

        vos.removeIf(field -> field.getFieldName().equals("dropOutTime"));
        vos.removeIf(field -> field.getFieldName().equals("billReturnType"));

        vos.removeIf(field -> field.getFieldName().equals("courseName"));
        vos.removeIf(field -> field.getFieldName().equals("periodsNum"));

        vos.removeIf(field -> field.getFieldName().equals("studentId"));
        vos.removeIf(field -> field.getFieldName().equals("studentName"));
        vos.removeIf(field -> field.getFieldName().equals("orderPoolStatus"));
        vos.removeIf(field -> field.getFieldName().equals("collectPeriods"));
        vos.removeIf(field -> field.getFieldName().equals("billTime"));

        vos.removeIf(field -> field.getFieldName().equals("type"));
        vos.removeIf(field -> field.getFieldName().equals("checkTime"));
        vos.removeIf(field -> field.getFieldName().equals("riskLevel"));
        vos.removeIf(field -> field.getFieldName().equals("createTime"));
        vos.removeIf(field -> field.getFieldName().equals("orgName"));
        vos.removeIf(field -> field.getFieldName().equals("preferentialMoney"));
        vos.removeIf(field -> field.getFieldName().equals("studentStatus"));// 入学状态

        //继承字段在新增修改页面不显示
        QueryWrapper<CrmField> customerQueryWrapper = new QueryWrapper<>();
        customerQueryWrapper.eq("label", CrmEnum.CUSTOMER.getType()).orderByAsc("sorting");
        customerQueryWrapper.ne("field_type", 1);
        List<CrmField> fields = crmFieldService.getBaseMapper().selectList(customerQueryWrapper);
        if(CollectionUtil.isNotEmpty(fields)){
            List<Integer> relevantIds = fields.stream().map(CrmField::getRelevant).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(relevantIds)){
                vos.removeIf(field -> relevantIds.contains(field.getFieldId()));
            }
        }

        return vos;
    }

    /**
     * 分页查询
     *
     * @param search
     * @return
     */
    @Override
    public BasePage<Map<String, Object>> queryPageList(CrmSearchBO search) {
        search.setLabel(CrmEnum.CONTRACT.getType());
        BasePage<Map<String, Object>> basePage = queryList(search);
        for (Map<String, Object> map : basePage.getList()) {
            Double contractMoney = StrUtil.isNotEmpty(map.get("money").toString()) ? Double.parseDouble(map.get("money").toString()) : 0D;
            BigDecimal receivedProgress = new BigDecimal(100);
            if (!contractMoney.equals(0D)) {
                receivedProgress = new BigDecimal(map.get("receivedMoney") != null ? Double.parseDouble(map.get("receivedMoney").toString()) : 0D).divide(new BigDecimal(contractMoney), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
            }
            map.put("receivedProgress", receivedProgress);

            //创建人名称回显
            if (ObjectUtil.isNotEmpty(map.get("createUserId"))) {
                Long createUserId = Long.valueOf(String.valueOf(map.get("createUserId")));
                if (ObjectUtil.isNotEmpty(createUserId)) {
                    String createUserName = UserCacheUtil.getUserName(createUserId);
                    map.put("createUserName", createUserName);
                }
            }

            // 负责人名称回显
            if (ObjectUtil.isNotEmpty(map.get("ownerUserId"))) {
                Long ownerUserId = Long.valueOf(String.valueOf(map.get("ownerUserId")));
                if (ObjectUtil.isNotEmpty(ownerUserId)) {
                    String ownerUserName = UserCacheUtil.getUserName(ownerUserId);
                    map.put("ownerUserName", ownerUserName);
                }
            }

            // 营销讲师名称回显
            if (ObjectUtil.isNotEmpty(map.get("teacherId"))) {
                Long teacherId = Long.valueOf(String.valueOf(map.get("teacherId")));
                if (ObjectUtil.isNotEmpty(teacherId)) {
                    String teacherName = UserCacheUtil.getUserName(teacherId);
                    map.put("teacherName", teacherName);
                }
            }

            //负责人所在部门
            if (ObjectUtil.isNotEmpty(map.get("ownerDeptId"))) {
                Long ownerDeptId = Long.valueOf(String.valueOf(map.get("ownerDeptId")));
                if (ObjectUtil.isNotEmpty(ownerDeptId)) {
                    String ownerDeptName = adminService.queryDeptName(Integer.valueOf(ownerDeptId.toString()));
                    map.put("ownerDeptName", ownerDeptName);
                }
            }

        }
        Map<String, Object> countMap = new HashMap<>();
        BigDecimal allMoney = new BigDecimal(0.00);
        BigDecimal yhMoney = new BigDecimal(0.00);
        BigDecimal whMoney = new BigDecimal(0.00);

        SearchRequest searchRequest = new SearchRequest(getIndex());
        searchRequest.types(getDocType());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = createQueryBuilder(search);
        queryBuilder.must(QueryBuilders.termQuery("checkStatus", 1));
        if(StringUtils.isBlank(search.getContractCategory())){
            queryBuilder.mustNot(QueryBuilders.termQuery("contractCategory", CrmBusinessConstEnum.账单类别_线下合同.getMsg()));
        }
        sourceBuilder.query(queryBuilder);
        sourceBuilder.aggregation(AggregationBuilders.sum("allMoney").field("money"));
        // 合同总金额
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchCount = elasticsearchRestTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchCount.getAggregations();
            ParsedSum contract = aggregations.get("allMoney");
            allMoney = new BigDecimal(contract.getValue());
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 已还金额
        SearchRequest searchOrderRequest = new SearchRequest(getIndex());
        searchOrderRequest.types(getDocType());
        SearchSourceBuilder sourceOrderBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryOrderBuilder = createQueryBuilder(search);
        queryOrderBuilder.must(QueryBuilders.termQuery("checkStatus", 1));
        sourceOrderBuilder.query(queryOrderBuilder);
        sourceOrderBuilder.aggregation(AggregationBuilders.sum("yhMoney").field("receivedMoney"));
        //已还金额
        searchOrderRequest.source(sourceOrderBuilder);
        try {
            SearchResponse searchCount = elasticsearchRestTemplate.getClient().search(searchOrderRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchCount.getAggregations();
            ParsedSum order = aggregations.get("yhMoney");
            yhMoney = new BigDecimal(order.getValue());
        } catch (IOException e) {
            e.printStackTrace();
        }

        SearchRequest searchSfkRequest = new SearchRequest(getIndex());
        searchSfkRequest.types(getDocType());
        SearchSourceBuilder sourceSfkBuilder = new SearchSourceBuilder();
        BoolQueryBuilder querySfkBuilder = createQueryBuilder(search);
        querySfkBuilder.must(QueryBuilders.termQuery("checkStatus", 1));
        sourceSfkBuilder.query(querySfkBuilder);
        sourceSfkBuilder.aggregation(AggregationBuilders.sum("whMoney").field("unreceivedMoney"));
        // 未还合同金额
        searchSfkRequest.source(sourceSfkBuilder);
        try {
            SearchResponse searchCount = elasticsearchRestTemplate.getClient().search(searchSfkRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchCount.getAggregations();
            ParsedSum contract = aggregations.get("whMoney");
            whMoney = new BigDecimal(contract.getValue());
        } catch (IOException e) {
            e.printStackTrace();
        }

        countMap.put("allMoney", allMoney.setScale(2, RoundingMode.HALF_UP));
        countMap.put("yhMoney", yhMoney.setScale(2, RoundingMode.HALF_UP));
        countMap.put("whMoney", whMoney.setScale(2, RoundingMode.HALF_UP));
        basePage.setExtraData(new JSONObject().fluentPut("money", countMap));
        return basePage;
    }

    @Override
    public BasePage<Map<String, Object>> queryPageListBill(CrmSearchBO search) {
        search.setLabel(CrmEnum.CONTRACT.getType());

        // 根据账单池配置查看当前用户是否有权限查看列表数据
        QueryWrapper<BillCrmOrderPool> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        BillCrmOrderPool orderPool = crmOrderPoolService.getBaseMapper().selectOne(queryWrapper);
        List<String> deptIds = Arrays.asList(orderPool.getMemberDeptId().split(","));

        List<Integer> allDeptIds = new ArrayList<>();
        for(String deptId : deptIds){
            allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(Integer.valueOf(deptId)));
            allDeptIds.add(Integer.valueOf(deptId));
        }

        if((!allDeptIds.contains(UserUtil.getUser().getDeptId())) && (!UserUtil.isAdmin())){
            BasePage<Map<String, Object>> basePage = new BasePage<>();
            basePage.setList(new ArrayList<>());
            basePage.setTotal(0);
            basePage.setCurrent(1);
            return basePage;
        }

        search.setOrderPoolId(orderPool.getOrderPoolId());

        BasePage<Map<String, Object>> basePage = queryList(search);
        for (Map<String, Object> map : basePage.getList()) {

            if (ObjectUtil.isNotEmpty(map.get("phone"))) {
                String phone = DesensitizedUtils.mobilePhone(map.get("phone").toString());
                map.put("phone", phone);
            }

        }
        return basePage;
    }

    /**
     * 查询字段配置
     *
     * @param id 主键ID
     * @return data
     */
    @Override
    public CrmModel queryById(Integer id) {
        CrmModel crmModel;
        if (id != null) {
            crmModel = getBaseMapper().queryById(id, UserUtil.getUserId());
            String contractType = (String) crmModel.get("type");
            crmModel.setLabel(CrmEnum.CONTRACT.getType());
            crmModel.setOwnerUserName(UserCacheUtil.getUserName(crmModel.getOwnerUserId()));
            List<String> nameList = StrUtil.splitTrim((String) crmModel.get("companyUserId"), Const.SEPARATOR);
            String name = nameList.stream().map(str -> UserCacheUtil.getUserName(Long.valueOf(str))).collect(Collectors.joining(Const.SEPARATOR));
            crmModel.put("companyUserName", name);
            crmModel.put("createUserName", UserCacheUtil.getUserName((Long) crmModel.get("createUserId")));
            crmContractDataService.setDataByBatchId(crmModel);
            List<String> stringList = SpringUtils.getBean(ICrmRoleFieldService.class).queryNoAuthField(crmModel.getLabel());
            List<String> deptFieldList = SpringUtils.getBean(ICrmDeptFieldService.class).queryNoAuthField(crmModel.getLabel());
            stringList = stringList.stream().filter(field -> deptFieldList.contains(field)).collect(Collectors.toList());

            stringList = stringList.stream().distinct().collect(Collectors.toList());
            stringList.forEach(crmModel::remove);
            Double contractMoney = crmModel.get("money") != null ? Double.parseDouble(crmModel.get("money").toString()) : 0D;
            BigDecimal receivedProgress = new BigDecimal(100);
            if (!contractMoney.equals(0D)) {
                receivedProgress = new BigDecimal(crmModel.get("receivedMoney") != null ? Double.parseDouble(crmModel.get("receivedMoney").toString()) : 0D).divide(new BigDecimal(contractMoney), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
            }
            crmModel.put("receivedProgress", receivedProgress);
            crmModel.put("type",contractType);
        } else {
            crmModel = new CrmModel(CrmEnum.CONTRACT.getType());
        }
        return crmModel;
    }

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 保存或新增信息
     *
     * @param crmModel model
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdate(CrmContractSaveBO crmModel) {
        CrmContract crmContract = BeanUtil.copyProperties(crmModel.getEntity(), CrmContract.class);
        String batchId = StrUtil.isNotEmpty(crmContract.getBatchId()) ? crmContract.getBatchId() : IdUtil.simpleUUID();
        actionRecordUtil.updateRecord(crmModel.getField(), Dict.create().set("batchId", batchId).set("dataTableName", "bill_crm_contract_data"));

        if(crmContract.getMoney().compareTo(new BigDecimal(0.00)) <= 0 || !Optional.ofNullable(crmContract.getMoney()).isPresent()){
            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_MONEY_GT_ZERO);
        }

        if (crmContract.getContractId() == null) {
            CrmModel customerModel = SpringUtils.getBean(ICrmCustomerService.class).queryById(crmContract.getCustomerId(), null);
            QueryWrapper<CrmField> customerQueryWrapper = new QueryWrapper<>();
            customerQueryWrapper.eq("label", CrmEnum.CUSTOMER.getType()).orderByAsc("sorting");
            customerQueryWrapper.ne("field_type", 1);
            List<CrmField> sourceFieldList = crmFieldService.getBaseMapper().selectList(customerQueryWrapper);

            QueryWrapper<CrmField> contractQueryWrapper = new QueryWrapper<>();
            contractQueryWrapper.eq("label", CrmEnum.CONTRACT.getType()).orderByAsc("sorting");
            contractQueryWrapper.ne("field_type", 1);
            List<CrmField> targeFieldList = crmFieldService.getBaseMapper().selectList(contractQueryWrapper);

            BeanExtendUtils im = new BeanExtendUtils(CrmCustomer.class, CrmContractData.class);
            List<CrmModelFiledVO> contractDataList = im.copyVoList(sourceFieldList, targeFieldList, customerModel);
            crmModel.getField().addAll(contractDataList);
        }
        crmContractDataService.saveData(crmModel.getField(), batchId);
        CrmCustomer customer = SpringUtils.getBean(ICrmCustomerService.class).getById(crmContract.getCustomerId());
        if(CrmRepaidStatusEnum.已退学.getRemarks().equals(customer.getRepaymentStatus())){
            throw new CrmException(CrmCodeEnum.CRM_CUSTOMER_IS_DROPOUT);
        }
//        String customerSource = SpringUtils.getBean(ICrmCustomerDataService.class).queryFieldValue("source",customer.getBatchId());
        if (crmContract.getStartTime() != null && crmContract.getEndTime() != null && crmContract.getStartTime().compareTo(crmContract.getEndTime()) > 0) {
            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_DATE_ERROR);
        }

        QueryWrapper<CrmContract> qeQueryWrapper = new QueryWrapper<>();
        qeQueryWrapper.eq("customer_id", crmContract.getCustomerId());
        qeQueryWrapper.in("check_status", Arrays.asList(1,3));
        qeQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_全款合同.getMsg());
        if(crmContract.getContractId() != null){
            qeQueryWrapper.ne("contract_id", crmContract.getContractId());
        }
        Integer qeCount = baseMapper.selectCount(qeQueryWrapper);
        if(qeCount > 0){
            // 提交失败，该学员有审核通过的全款合同。
            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_SUBMIT_ERROR_QK_CONTRACT);
        }

        if(CrmBusinessConstEnum.账单类别_线下合同.getMsg().equals(crmContract.getContractCategory())){
            QueryWrapper<CrmContract> bkQueryWrapper = new QueryWrapper<>();
            bkQueryWrapper.eq("customer_id", crmContract.getCustomerId());
            bkQueryWrapper.in("check_status", Arrays.asList(1,3));
            bkQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_线下合同.getMsg());
            if(crmContract.getContractId() != null){
                bkQueryWrapper.ne("contract_id", crmContract.getContractId());
            }
            Integer bkCount = baseMapper.selectCount(bkQueryWrapper);
            if(bkCount > 0){
                // 提交失败，该学员有审核通过的线下合同。
                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_SUBMIT_ERROR_TXBK_CONTRACT);
            }
        }else{
            QueryWrapper<CrmContract> zdQueryWrapper = new QueryWrapper<>();
            zdQueryWrapper.eq("customer_id", crmContract.getCustomerId());
            zdQueryWrapper.in("check_status", Arrays.asList(1,3));
            zdQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_账单合同.getMsg());
            if(crmContract.getContractId() != null){
                zdQueryWrapper.ne("contract_id", crmContract.getContractId());
            }
            Integer zdCount = baseMapper.selectCount(zdQueryWrapper);
            if(zdCount > 0){
                // 提交失败，该学员已绑定账单合同。
                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_SUBMIT_ERROR_ZD_CONTRACT);
            }

            QueryWrapper<CrmContract> sfkQueryWrapper = new QueryWrapper<>();
            sfkQueryWrapper.eq("customer_id", crmContract.getCustomerId());
            sfkQueryWrapper.in("check_status", Arrays.asList(1,3));
            sfkQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_首付款合同.getMsg());
            if(crmContract.getContractId() != null){
                sfkQueryWrapper.ne("contract_id", crmContract.getContractId());
            }
            Integer sfkCount = baseMapper.selectCount(sfkQueryWrapper);
            if(sfkCount > 0){
                // 提交失败，该学员有审核通过的首付款合同。
                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_SUBMIT_ERROR_SFK_CONTRACT);
            }
        }


        if (crmContract.getDiscountRate() == null) {
            crmContract.setDiscountRate(new BigDecimal("0"));
        }
//        Integer examineCount = crmExamineService.queryCount(getLabel());
        ExamineRecordSaveBO examineRecordSaveBO = crmModel.getExamineFlowData();
        ExamineRecordReturnVO examineData = null;

        //是否重复
        crmContract.setIsRepetition(customer.getIsRepetition());
        crmContract.setStudentName(customer.getCustomerName());
        crmContract.setLeadsFormTime(customer.getLeadsFormTime());

        boolean isUpdate = false;
        CrmContract oldContract = new CrmContract();
        if (crmContract.getContractId() == null) {

            List<AdminConfigBo> configList = adminService.queryConfigByName("numberSetting");
            AdminConfigBo adminConfig = configList.stream().filter(config -> Objects.equals(getLabel().getType().toString(), config.getValue())).collect(Collectors.toList()).get(0);
            if (adminConfig.getStatus() == 1 && StrUtil.isEmpty(crmContract.getNum())) {
                String result = crmNumberSettingService.generateNumber(adminConfig, crmContract.getOrderDate());
                crmContract.setNum(result);
            }
            Integer contract = lambdaQuery().eq(CrmContract::getNum, crmContract.getNum()).ne(CrmContract::getCheckStatus, 7).count();
            if (contract != 0) {
                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_NUM_ERROR);
            }

            CrmStudent student = crmStudentService.queryStudentBySerialNumber(customer.getSerialNumber());
            if(BeanUtil.isNotEmpty(student)){
                crmContract.setStudentId(student.getStudentId());
            }

            crmContract.setUnreceivedMoney(crmContract.getMoney());
            crmContract.setReceivedMoney(new BigDecimal("0"));
            crmContract.setCreateUserId(UserUtil.getUserId());
            crmContract.setBatchId(batchId);
            if (ObjectUtil.isEmpty(crmContract.getCreateTime())) {
                crmContract.setCreateTime(DateUtil.date());
            }
            crmContract.setUpdateTime(DateUtil.date());
            crmContract.setRoUserId(",");
            crmContract.setRwUserId(",");
            crmContract.setOwnerUserId(UserUtil.getUserId());
            crmContract.setCurrencyName("人民币");
            crmContract.setBackStatus("未回款");
            crmContract.setDueMonery(crmContract.getMoney());
            crmContract.setRefundMonery(new BigDecimal(0));
            crmContract.setInvoicedMonery(new BigDecimal(0));
            crmContract.setUninvoicedMonery(crmContract.getMoney());
            crmContract.setOrderDate(DateUtil.parse(DateUtil.formatDateTime(new Date()), "yyyy-MM-dd"));
            crmContract.setDiscountRate(new BigDecimal(100));
            crmContract.setSource(customer.getSource());
            crmContract.setDealStatus("未成交");
            crmContract.setRiskLevel(CrmBusinessConstEnum.风险提示_正常.getMsg());
            // 设置合同来源
            crmContract.setType("人工创建");
            // 初始入学状态
            crmContract.setStudentStatus(CrmBusinessConstEnum.入学状态_已入学.getMsg());

            save(crmContract);
            if (crmContract.getCheckStatus() != null && crmContract.getCheckStatus() == 5) {
                crmContract.setCheckStatus(5);
            } else {
                //审批信息置空 用于创建合同时直接审批通过 并且 将客户 置为已成交
//                examineRecordSaveBO = null;
                if (examineRecordSaveBO != null) {
                    this.supplementFieldInfo(1, crmContract.getContractId(), null, examineRecordSaveBO);
                    examineRecordSaveBO.setTitle(crmContract.getName());
                    examineRecordSaveBO.setSubmitUserId(UserUtil.getUserId());
                    examineData = examineService.addExamineRecord(examineRecordSaveBO);
                    crmContract.setExamineRecordId(examineData.getRecordId());
                    crmContract.setCheckStatus(examineData.getExamineStatus());
                } else {
                    crmContract.setCheckStatus(1);
                    crmContract.setCheckTime(DateUtil.date());
                }
            }
            updateById(crmContract);
            crmActivityService.addActivity(2, CrmActivityEnum.CONTRACT, crmContract.getContractId());
            actionRecordUtil.addRecord(crmContract.getContractId(), CrmEnum.CONTRACT, crmContract.getName());

            //更新联系人中回款状态
            CrmContacts crmContacts = SpringUtils.getBean(ICrmContactsService.class).getContactsByCustomerId(crmContract.getCustomerId());
            if (crmContacts != null) {
                crmContacts.setBackStatus("未回款");

                SpringUtils.getBean(ICrmContactsService.class).updateById(crmContacts);

                //更新ES数据
                Map<String, Object> map = new HashMap<>();
                map.put("backStatus", "未回款");
                ElasticUtil.updateField(elasticsearchRestTemplate, map, crmContacts.getContactsId(), CrmEnum.CONTACTS.getIndex());
            }


        } else {
            isUpdate = true;
            CrmContract contract = getById(crmContract.getContractId());

            if(!"人工创建".equals(contract.getType())){
                throw new CrmException(CrmCodeEnum.CRM_ORDER_NO_AUTH_UPDATE);
            }

            BeanUtils.copyProperties(contract, oldContract);
            if (contract.getCheckStatus() == 8) {
                contract.setCheckStatus(5);
            }
            if (contract.getCheckStatus() == 1) {
                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_EXAMINE_PASS_HINT_ERROR);
            }
            //判断金额
            BigDecimal oldMonery = contract.getMoney();
            BigDecimal newMonery = crmContract.getMoney();
            //新老 成交金额不相等
            if (oldMonery.compareTo(newMonery) != 0) {
                //原始已回款金额
                BigDecimal receivedMoney = contract.getReceivedMoney();
                if (newMonery.compareTo(receivedMoney) < 0) {
                    throw new CrmException(CrmCodeEnum.THE_MONERY_LESS_THAN_THE_RECEIVE_MONERY);
                }
                String backStatus = "";
                if (newMonery.compareTo(receivedMoney) == 0) {
                    backStatus = "已回款";
                    crmContract.setUnreceivedMoney(new BigDecimal(0));
                    crmContract.setBackStatus("已回款");
                    crmContract.setDueMonery(newMonery);
                    crmContract.setReceivedMoney(contract.getReceivedMoney());
                } else {
                    backStatus = "未回款";
                    BigDecimal unreceivedMoney = contract.getUnreceivedMoney();
                    unreceivedMoney = unreceivedMoney.add(newMonery.subtract(oldMonery));
                    crmContract.setUnreceivedMoney(unreceivedMoney);
                    crmContract.setDueMonery(newMonery);
                    crmContract.setReceivedMoney(contract.getReceivedMoney());
                    crmContract.setBackStatus("未回款");
                }
                //更新联系人中回款状态
                CrmContacts crmContacts = SpringUtils.getBean(ICrmContactsService.class).getContactsByCustomerId(crmContract.getCustomerId());
                if (crmContacts != null) {
                    crmContacts.setBackStatus(backStatus);

                    SpringUtils.getBean(ICrmContactsService.class).updateById(crmContacts);
                    Map<String, Object> map = new HashMap<>();
                    map.put("backStatus", backStatus);
                    ElasticUtil.updateField(elasticsearchRestTemplate, map, crmContacts.getContactsId(), CrmEnum.CONTACTS.getIndex());
                }
            }

//            if (contract.getCheckStatus() == 0){
//                contract.setCheckStatus(4);
//            }
//            if (contract.getCheckStatus() != 4 && contract.getCheckStatus() != 2 && contract.getCheckStatus() != 5) {
//                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_EDIT_ERROR);
//            }
            crmContract.setSource(customer.getSource());

            //编辑时 直接审批通过
//            examineRecordSaveBO = null;
            if (crmContract.getCheckStatus() != null && crmContract.getCheckStatus() == 5) {
                crmContract.setCheckStatus(5);
            } else {
                if (examineRecordSaveBO != null) {
                    this.supplementFieldInfo(1, crmContract.getContractId(), contract.getExamineRecordId(), examineRecordSaveBO);
                    examineRecordSaveBO.setTitle(crmContract.getName());
                    examineRecordSaveBO.setSubmitUserId(UserUtil.getUserId());
                    examineData = examineService.addExamineRecord(examineRecordSaveBO);
                    crmContract.setExamineRecordId(examineData.getRecordId());
                    crmContract.setCheckStatus(examineData.getExamineStatus());
                } else {
                    crmContract.setCheckStatus(1);
                }
            }
            crmBackLogDealService.deleteByType(crmContract.getOwnerUserId(), CrmEnum.CONTRACT, CrmBackLogEnum.END_CONTRACT, crmContract.getContractId());
            crmBackLogDealService.deleteByType(crmContract.getOwnerUserId(), CrmEnum.CONTRACT, CrmBackLogEnum.REMIND_RETURN_VISIT_CONTRACT, crmContract.getContractId());
            crmContract.setUpdateTime(DateUtil.date());
            actionRecordUtil.updateRecord(BeanUtil.beanToMap(contract), BeanUtil.beanToMap(crmContract), CrmEnum.CONTRACT, crmContract.getName(), crmContract.getContractId());
            updateById(crmContract);
            crmContract = getById(crmContract.getContractId());
            ElasticUtil.batchUpdateEsData(elasticsearchRestTemplate.getClient(), "contract", crmContract.getContractId().toString(), crmContract.getName());
        }

        //判断当前是否提交审核，提交审核需要生成一条系统通知
        if (0 == crmContract.getCheckStatus()) {
            if (examineData != null) {
                actionRecordUtil.addCrmExamineActionRecord(CrmEnum.CONTRACT, examineData.getRecordId(), BehaviorEnum.SUBMIT_EXAMINE, crmContract.getNum());
            }
        }
        List<CrmContractProduct> contractProductList = crmModel.getProduct();
        crmContractProductService.deleteByContractId(crmContract.getContractId());
        if (crmContract.getBusinessId() != null) {
            crmBusinessProductService.deleteByBusinessId(crmContract.getBusinessId());
        }
        if (contractProductList != null) {
            for (CrmContractProduct crmContractProduct : contractProductList) {
                crmContractProduct.setContractId(crmContract.getContractId());
                crmContractProductService.save(crmContractProduct);
                if (crmContract.getBusinessId() != null) {
                    CrmBusinessProduct crmBusinessProduct = BeanUtil.copyProperties(crmContractProduct, CrmBusinessProduct.class);
                    crmBusinessProduct.setRId(null);
                    crmBusinessProduct.setBusinessId(crmContract.getBusinessId());
                    crmBusinessProductService.save(crmBusinessProduct);
                }
            }
        }
        crmModel.setEntity(BeanUtil.beanToMap(crmContract));
        savePage(crmModel, crmContract.getContractId(), false);

        if(isUpdate){
            if(!ObjectUtil.equal(crmContract.getTeacherId(), oldContract.getTeacherId())){
                String teacherName = UserCacheUtil.getUserName(crmContract.getTeacherId());

                if(oldContract.getTeacherId() != null){
                    addMessage(crmContract.getName(),teacherName,oldContract.getTeacherId(),AdminMessageEnum.CRM_CONTRACT_CHANGE_TEACHER_USER.getType(),crmContract.getContractId());
                }

                if(crmContract.getTeacherId() != null){
                    addMessage(crmContract.getName(),teacherName,crmContract.getTeacherId(),AdminMessageEnum.CRM_CONTRACT_CHANGE_TEACHER_USER.getType(),crmContract.getContractId());
                }
            }
        }
    }

    @Autowired
    private ICrmBusinessService crmBusinessService;

    @Autowired
    private ICrmContactsService crmContactsService;

    @Override
    public void setOtherField(Map<String, Object> map) {
        String customerName = crmCustomerService.getCustomerName((Integer) map.get("customerId"));
        map.put("customerName", customerName);
        if (map.containsKey("businessId") && ObjectUtil.isNotEmpty(map.get("businessId"))) {
            String businessName = crmBusinessService.getBusinessName((Integer) map.get("businessId"));
            map.put("businessName", businessName);
        } else {
            map.put("businessName", "");
        }
        if (map.containsKey("contactsId") && ObjectUtil.isNotEmpty(map.get("contactsId"))) {
            String contactsName = crmContactsService.getContactsName((Integer) map.get("contactsId"));
            map.put("contactsName", contactsName);
        } else {
            map.put("contactsName", "");
        }
        if (map.containsKey("companyUserId") && ObjectUtil.isNotEmpty(map.get("companyUserId"))) {
            String companyUserName = adminService.queryUserByIds(TagUtil.toLongList(map.get("companyUserId").toString()))
                    .stream().map(SimpleUser::getRealname).collect(Collectors.joining(","));
            map.put("companyUserName", companyUserName);
        } else {
            map.put("companyUserName", "");
        }
        if (map.containsKey("ownerUserId") && ObjectUtil.isNotEmpty(map.get("ownerUserId"))) {
            String ownerUserName = UserCacheUtil.getUserName((Long) map.get("ownerUserId"));
            map.put("ownerUserName", ownerUserName);
        } else {
            map.put("ownerUserName", "");
        }
        String createUserName = UserCacheUtil.getUserName((Long) map.get("createUserId"));
        map.put("createUserName", createUserName);

        String teacherName = UserCacheUtil.getUserName((Long) map.get("teacherId"));
        map.put("teacherName", teacherName);
    }

    @Override
    public Dict getSearchTransferMap() {
        return Dict.create().set("customerId", "customerName").set("businessId", "businessName").set("contactsId", "contactsName");
    }

    /**
     * 删除合同数据
     *
     * @param ids ids
     */
    @Override
    public void deleteByIds(List<Integer> ids) {
        //合同
        Integer number = SpringUtils.getBean(ICrmReceivablesService.class).lambdaQuery().in(CrmReceivables::getContractId, ids).ne(CrmReceivables::getCheckStatus, 7).count();
        Integer refundNumber = SpringUtils.getBean(ICrmReFundService.class).lambdaQuery().in(CrmRefund::getContractId, ids).ne(CrmRefund::getCheckStatus, 7).count();
        if (number > 0 || refundNumber > 0) {
            throw new CrmException(CrmCodeEnum.CRM_DATA_JOIN_ERROR);
        }

        Integer receivablesNum = crmReceivablesService.lambdaQuery().ne(CrmReceivables::getCheckStatus,7).in(CrmReceivables::getContractId, ids).count();
        if (receivablesNum > 0) {
            throw new CrmException(CrmCodeEnum.CRM_DATA_JOIN_ERROR);
        }

        List<CrmContract> contractList = lambdaQuery().in(CrmContract::getContractId, ids).ne(CrmContract::getCheckStatus, 7).list();
        for(CrmContract contract : contractList){
            if(!"人工创建".equals(contract.getType())){
                throw new CrmException(CrmCodeEnum.CRM_ORDER_NO_AUTH_DELETE);
            }
        }

        ids.forEach(id -> {
            CrmContract contract = getById(id);
            boolean bol = (contract.getCheckStatus() != 4 && contract.getCheckStatus() != 5) && (!(UserUtil.isAdmin()));
            if (bol) {
                throw new CrmException(CrmCodeEnum.CAN_ONLY_DELETE_WITHDRAWN_AND_SUBMITTED_EXAMINE);
            }
            //删除合同产品关联
            crmContractProductService.deleteByContractId(contract.getContractId());
            //删除跟进记录
            crmActivityService.deleteActivityRecord(CrmActivityEnum.CONTRACT, Collections.singletonList(id));
            //删除字段操作记录
            crmActionRecordService.deleteActionRecord(CrmEnum.CONTRACT, Collections.singletonList(contract.getContractId()));
            //删除自定义字段
            crmContractDataService.deleteByBatchId(Collections.singletonList(contract.getBatchId()));
            //删除文件
            adminFileService.delete(Collections.singletonList(contract.getBatchId()));
            if (ObjectUtil.isNotEmpty(contract.getExamineRecordId())) {
                examineService.deleteExamineRecord(contract.getExamineRecordId());
            }
            contract.setCheckStatus(7);
            updateById(contract);
        });
        deletePage(ids);
    }

    /**
     * 修改合同负责人
     *
     * @param changOwnerUserBO data
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeOwnerUser(CrmBusinessChangOwnerUserBO changOwnerUserBO) {
        if (changOwnerUserBO.getIds().size() == 0) {
            return;
        }
        String ownerUserName = UserCacheUtil.getUserName(changOwnerUserBO.getOwnerUserId());
        changOwnerUserBO.getIds().forEach(id -> {
            if (AuthUtil.isRwAuth(id, CrmEnum.CONTRACT)) {
                throw new CrmException(SystemCodeEnum.SYSTEM_NO_AUTH);
            }
            CrmContract contract = getById(id);
            if (contract.getCheckStatus() == 8) {
                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_TRANSFER_ERROR);
            }
            String memberId = "," + changOwnerUserBO.getOwnerUserId() + ",";
            getBaseMapper().deleteMember(memberId, id);
            contract = getById(id);
            Long oldOwnerUserId = contract.getOwnerUserId();
            if (2 == changOwnerUserBO.getTransferType() && !changOwnerUserBO.getOwnerUserId().equals(contract.getOwnerUserId())) {
                if (1 == changOwnerUserBO.getPower()) {
                    contract.setRoUserId(contract.getRoUserId() + contract.getOwnerUserId() + Const.SEPARATOR);
                }
                if (2 == changOwnerUserBO.getPower()) {
                    contract.setRwUserId(contract.getRwUserId() + contract.getOwnerUserId() + Const.SEPARATOR);
                }
                crmCustomerService.addTermMessage(AdminMessageEnum.CRM_CONTRACT_USER, contract.getContractId(), contract.getName(), contract.getOwnerUserId());
            }
            contract.setOwnerUserId(changOwnerUserBO.getOwnerUserId());
            updateById(contract);
            actionRecordUtil.addConversionRecord(id, CrmEnum.CONTRACT, changOwnerUserBO.getOwnerUserId(), contract.getName());
            //修改es
            Map<String, Object> map = new HashMap<>();
            map.put("ownerUserId", changOwnerUserBO.getOwnerUserId());
            map.put("ownerUserName", ownerUserName);
            map.put("rwUserId", contract.getRwUserId());
            map.put("roUserId", contract.getRoUserId());
            updateField(map, Collections.singletonList(id));

            if(!ObjectUtil.equal(oldOwnerUserId,changOwnerUserBO.getOwnerUserId())){
                if((!UserUtil.getUserId().equals(oldOwnerUserId)) && (oldOwnerUserId != null)){
                    addMessage(contract.getName(),ownerUserName,oldOwnerUserId,AdminMessageEnum.CRM_CONTRACT_CHANGE_OWNER_USER.getType(),contract.getContractId());
                }
                if((!UserUtil.getUserId().equals(changOwnerUserBO.getOwnerUserId())) && changOwnerUserBO.getOwnerUserId() != null){
                    addMessage(contract.getName(),ownerUserName,changOwnerUserBO.getOwnerUserId(),AdminMessageEnum.CRM_CONTRACT_CHANGE_OWNER_USER.getType(),contract.getContractId());
                }
            }

        });

    }

    /**
     * 修改合同讲师负责人
     * @param ownerUserBO
     */
    @Override
    public void changeTeacherUser(CrmChangeOwnerUserBO ownerUserBO){
        QueryWrapper<CrmContract> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("contract_id", ownerUserBO.getIds());
        queryWrapper.notIn("check_status", 7);
        List<CrmContract> crmContractList = query().getBaseMapper().selectList(queryWrapper);

        LambdaUpdateWrapper<CrmContract> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CrmContract::getTeacherId, ownerUserBO.getTeacherId());
        updateWrapper.in(CrmContract::getContractId, ownerUserBO.getIds());
        update(updateWrapper);

        String teacherName = UserCacheUtil.getUserName(ownerUserBO.getTeacherId());

        // 操作记录
        for (Integer id : ownerUserBO.getIds()) {
            actionRecordUtil.conversionTeacherRecordAdd(id,CrmEnum.CONTRACT,ownerUserBO.getTeacherId(),getById(id).getNum());
        }

        //修改es
        Map<String, Object> map = new HashMap<>();
        map.put("teacherId", ownerUserBO.getTeacherId());
        map.put("teacherName", teacherName);
        updateField(map, ownerUserBO.getIds());

        // 发送消息
        for(CrmContract contract : crmContractList){
            if(!ObjectUtil.equal(contract.getTeacherId(),ownerUserBO.getTeacherId())){
                if((!UserUtil.getUserId().equals(contract.getTeacherId())) && (contract.getTeacherId() != null)){
                    addMessage(contract.getNum(),teacherName,contract.getTeacherId(),AdminMessageEnum.CRM_CONTRACT_CHANGE_TEACHER_USER.getType(),contract.getContractId());
                }

                if((!UserUtil.getUserId().equals(ownerUserBO.getTeacherId())) && ownerUserBO.getTeacherId() != null){
                    addMessage(contract.getNum(),teacherName,ownerUserBO.getTeacherId(),AdminMessageEnum.CRM_CONTRACT_CHANGE_TEACHER_USER.getType(),contract.getContractId());
                }
            }
        }
    }


    /**
     * 全部导出
     *
     * @param response resp
     * @param search   搜索对象
     */
    @Override
    public void exportExcel(HttpServletResponse response, CrmSearchBO search) {
        List<Map<String, Object>> dataList = queryPageList(search).getList();
        try (ExcelWriter writer = ExcelUtil.getWriter()) {
            List<CrmFieldSortVO> headList = crmFieldService.queryListHead(getLabel().getType());
            headList.forEach(head -> writer.addHeaderAlias(head.getFieldName(), head.getName()));
            writer.merge(headList.size() - 1, "合同信息");
            if (dataList.size() == 0) {
                Map<String, Object> record = new HashMap<>();
                headList.forEach(head -> record.put(head.getFieldName(), ""));
                dataList.add(record);
            }
            for (Map<String, Object> map : dataList) {
                if (map.get("checkStatus") == null || "".equals(map.get("checkStatus"))) {
                    continue;
                }
                String checkStatus;
                //0待审核、1通过、2拒绝、3审核中 4:撤回 5 未提交 6 创建 7 已删除 8 作废
                switch ((Integer) map.get("checkStatus")) {
                    case 1:
                        checkStatus = "通过";
                        break;
                    case 2:
                        checkStatus = "拒绝";
                        break;
                    case 3:
                        checkStatus = "审核中";
                        break;
                    case 4:
                        checkStatus = "撤回";
                        break;
                    case 5:
                        checkStatus = "未提交";
                        break;
                    case 7:
                        checkStatus = "已删除";
                        break;
                    case 8:
                        checkStatus = "作废";
                        break;
                    default:
                        checkStatus = "待审核";
                }
                map.put("checkStatus", checkStatus);
            }
            writer.setOnlyAlias(true);
            writer.write(dataList, true);
            writer.setRowHeight(0, 20);
            writer.setRowHeight(1, 20);
            for (int i = 0; i < headList.size(); i++) {
                writer.setColumnWidth(i, 20);
            }
            Cell cell = writer.getCell(0, 0);
            CellStyle cellStyle = cell.getCellStyle();
            cellStyle.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            Font font = writer.createFont();
            font.setBold(true);
            font.setFontHeightInPoints((short) 16);
            cellStyle.setFont(font);
            cell.setCellStyle(cellStyle);
            //自定义标题别名
            //response为HttpServletResponse对象
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
            String fileName = "合同" + DateUtils.dateTimeNow() + ".xls";
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8"));
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out);

            // 新增消息
            addMessage(String.valueOf(dataList.size()),"导出数据" + String.valueOf(dataList.size()) + "条",UserUtil.getUserId(),AdminMessageEnum.CRM_CONTRACT_EXPORT.getType(),null);

        } catch (Exception e) {
            log.error("导出合同错误：", e);
        }
    }


    /**
     * 获取团队成员
     *
     * @param contractId 合同ID
     * @return data
     */
    @Override
    public List<CrmMembersSelectVO> getMembers(Integer contractId) {
        CrmContract crmContract = getById(contractId);
        List<CrmMembersSelectVO> recordList = new ArrayList<>();
        if (crmContract.getOwnerUserId() != null) {
            UserInfo userInfo = UserCacheUtil.getUserInfo(crmContract.getOwnerUserId());
            CrmMembersSelectVO crmMembersVO = new CrmMembersSelectVO();
            crmMembersVO.setUserId(userInfo.getUserId());
            crmMembersVO.setRealname(UserCacheUtil.getUserName(userInfo.getUserId()));
            crmMembersVO.setDeptName(UserCacheUtil.getDeptName(userInfo.getDeptId()));
            crmMembersVO.setPower("负责人权限");
            crmMembersVO.setGroupRole("负责人");
            crmMembersVO.setPost(userInfo.getPost());
            recordList.add(crmMembersVO);
        }
        String roUserId = crmContract.getRoUserId();
        String rwUserId = crmContract.getRwUserId();
        String memberIds = roUserId + rwUserId.substring(1);
        if (Const.SEPARATOR.equals(memberIds)) {
            return recordList;
        }
        String[] memberIdsArr = memberIds.substring(1, memberIds.length() - 1).split(",");
        Set<String> memberIdsSet = new HashSet<>(Arrays.asList(memberIdsArr));
        for (String memberId : memberIdsSet) {
            UserInfo userInfo = UserCacheUtil.getUserInfo(Long.valueOf(memberId));
            CrmMembersSelectVO crmMembersVO = new CrmMembersSelectVO();
            crmMembersVO.setUserId(userInfo.getUserId());
            crmMembersVO.setRealname(UserCacheUtil.getUserName(userInfo.getUserId()));
            crmMembersVO.setDeptName(UserCacheUtil.getDeptName(userInfo.getDeptId()));
            crmMembersVO.setGroupRole("普通成员");
            crmMembersVO.setPost(userInfo.getPost());
            if (roUserId.contains(memberId)) {
                crmMembersVO.setPower("只读");
            } else if (rwUserId.contains(memberId)) {
                crmMembersVO.setPower("读写");
            }
            recordList.add(crmMembersVO);
        }
        return recordList;
    }

    /**
     * 添加团队成员
     *
     * @param crmMemberSaveBO data
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMember(CrmMemberSaveBO crmMemberSaveBO) {
        for (Integer id : crmMemberSaveBO.getIds()) {
            if (AuthUtil.isCrmOperateAuth(CrmEnum.CONTRACT, id)) {
                throw new CrmException(SystemCodeEnum.SYSTEM_NO_AUTH);
            }
            CrmContract oldContract = lambdaQuery().eq(CrmContract::getContractId, id).ne(CrmContract::getCheckStatus, 7).one();
            if (oldContract == null) {
                continue;
            }
            Long ownerUserId = oldContract.getOwnerUserId();
            for (Long memberId : crmMemberSaveBO.getMemberIds()) {
                if (ownerUserId.equals(memberId)) {
                    throw new CrmException(CrmCodeEnum.CRM_MEMBER_ADD_ERROR);
                }
                oldContract.setRoUserId(oldContract.getRoUserId().replace(Const.SEPARATOR + memberId.toString() + Const.SEPARATOR, Const.SEPARATOR));
                oldContract.setRwUserId(oldContract.getRwUserId().replace(Const.SEPARATOR + memberId.toString() + Const.SEPARATOR, Const.SEPARATOR));
                String name = lambdaQuery().select(CrmContract::getName).eq(CrmContract::getContractId, id).one().getName();
                crmCustomerService.addTermMessage(AdminMessageEnum.CRM_CONTRACT_USER, oldContract.getContractId(), oldContract.getName(), memberId);
                actionRecordUtil.addMemberActionRecord(CrmEnum.BUSINESS, id, memberId, name);
            }
            if (1 == crmMemberSaveBO.getPower()) {
                oldContract.setRoUserId(oldContract.getRoUserId() + StrUtil.join(Const.SEPARATOR, crmMemberSaveBO.getMemberIds()) + Const.SEPARATOR);
            } else if (2 == crmMemberSaveBO.getPower()) {
                oldContract.setRwUserId(oldContract.getRwUserId() + StrUtil.join(Const.SEPARATOR, crmMemberSaveBO.getMemberIds()) + Const.SEPARATOR);
            }
            updateById(oldContract);
            Map<String, Object> map = new HashMap<>();
            map.put("roUserId", oldContract.getRoUserId());
            map.put("rwUserId", oldContract.getRwUserId());
            updateField(map, Collections.singletonList(id));
        }
    }

    /**
     * 删除团队成员
     *
     * @param crmMemberSaveBO data
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMember(CrmMemberSaveBO crmMemberSaveBO) {
        for (Integer id : crmMemberSaveBO.getIds()) {
            if (AuthUtil.isCrmOperateAuth(CrmEnum.CONTRACT, id)) {
                throw new CrmException(SystemCodeEnum.SYSTEM_NO_AUTH);
            }
            deleteMembers(id, crmMemberSaveBO.getMemberIds());
        }
    }

    private void deleteMembers(Integer id, List<Long> memberIds) {
        CrmContract oldContract = getById(id);
        Long ownerUserId = oldContract.getOwnerUserId();
        for (Long memberId : memberIds) {
            if (ownerUserId.equals(memberId)) {
                throw new CrmException(CrmCodeEnum.CRM_MEMBER_DELETE_ERROR);
            }
            oldContract.setRoUserId(oldContract.getRoUserId().replace(Const.SEPARATOR + memberId.toString() + Const.SEPARATOR, Const.SEPARATOR));
            oldContract.setRwUserId(oldContract.getRwUserId().replace(Const.SEPARATOR + memberId.toString() + Const.SEPARATOR, Const.SEPARATOR));
            if (!memberId.equals(UserUtil.getUserId())) {
                crmCustomerService.addTermMessage(AdminMessageEnum.CRM_CONTRACT_REMOVE_TEAM, oldContract.getContractId(), oldContract.getName(), memberId);
                actionRecordUtil.addDeleteMemberActionRecord(CrmEnum.CONTRACT, id, memberId, false, oldContract.getName());
            } else {
                crmCustomerService.addTermMessage(AdminMessageEnum.CRM_CONTRACT_TEAM_EXIT, oldContract.getContractId(), oldContract.getName(), oldContract.getOwnerUserId());
                actionRecordUtil.addDeleteMemberActionRecord(CrmEnum.CONTRACT, id, memberId, true, oldContract.getName());
            }
        }
        updateById(oldContract);
        Map<String, Object> map = new HashMap<>();
        map.put("roUserId", oldContract.getRoUserId());
        map.put("rwUserId", oldContract.getRwUserId());
        updateField(map, Collections.singletonList(id));
    }

    /**
     * 退出团队
     *
     * @param contractId 合同ID
     */
    @Override
    public void exitTeam(Integer contractId) {
        deleteMembers(contractId, Collections.singletonList(UserUtil.getUserId()));
    }

    @Override
    public List<CrmModelFiledVO> information(Integer contractId) {
        CrmModel crmModel = queryById(contractId);
        Set<String> set  = crmModel.keySet();
        List<String> keyList = new ArrayList<>(set);
        List<String> systemFieldList = Arrays.asList("checkStatus","checkTime","periodsNum","repaymentStatus","riskLevel","dropOutTime","repairMoney","collectPeriods",
                "billTime","recentBackTime","type","billReturnType","createUserName", "createTime", "updateTime", "lastTime", "receivedMoney", "unreceivedMoney");
//        List<String> systemFieldList = Arrays.asList("createUserName", "createTime", "updateTime", "", "下次联系时间", "lastTime", "receivedMoney", "unreceivedMoney");
//        List<String> systemFieldList = Arrays.asList("创建人", "创建时间", "更新时间", "是否成交", "下次联系时间", "最后跟进时间", "已收款金额", "未收款金额");
        List<CrmModelFiledVO> crmModelFiledVOS = queryInformation(crmModel, keyList);

        CrmModelFiledVO customerField = crmModelFiledVOS.stream().filter(item -> "customerId".equals(item.getFieldName())).collect(Collectors.toList()).get(0);

        crmModelFiledVOS.removeIf(item -> Arrays.asList("businessId","contactsId","companyUserId","customerId").contains(item.getFieldName()));

        crmModelFiledVOS.add(new CrmModelFiledVO().setFieldName("checkStatus").setName("审核状态").setValue(crmModel.get("checkStatus")).setFormType("check_status").setFieldType(1));
        crmModelFiledVOS.add(customerField.getSorting(),new CrmModelFiledVO().setFieldName("customerId").setName("客户名称").setValue(new JSONObject().fluentPut("customerId", crmModel.get("customerId")).fluentPut("customerName", crmModel.get("customerName"))).setFormType("customer").setFieldType(1));

        return crmModelFiledVOS.stream().sorted(Comparator.comparingInt(r -> -r.getFieldType())).peek(r -> {
            r.setFieldType(null);
            r.setSetting(null);
            r.setType(null);
            r.setAuthLevel(2);
            if (systemFieldList.contains(r.getFieldName())) {
                r.setSysInformation(1);
            } else {
                r.setSysInformation(0);
            }
        }).collect(Collectors.toList());
    }

    /**
     * 查询产品通过合同ID
     *
     * @param crmRelationPageBO 合同ID
     * @return data
     */
    @Override
    public JSONObject queryProductListByContractId(CrmRelationPageBO crmRelationPageBO) {
        JSONObject record = getBaseMapper().querySubtotalByContractId(crmRelationPageBO.getContractId());
        if (record.getString("money") == null) {
            record.put("money", 0);
        }
        BasePage<JSONObject> page = getBaseMapper().queryProductPageList(crmRelationPageBO.parse(), crmRelationPageBO.getContractId());
        for (JSONObject jsonObject : page.getList()) {
            Integer status = jsonObject.getInteger("status");
            if (status == 1) {
                jsonObject.put("是否上下架", "是");
            } else {
                jsonObject.put("是否上下架", "否");
            }
        }
        record.put("pageNumber", page.getPageNumber());
        record.put("pageSize", page.getPageSize());
        record.put("totalPage", page.getTotalPage());
        record.put("totalRow", page.getTotalRow());
        record.put("list", page.getList());
        return record;
    }

    /**
     * 查询文件数量
     *
     * @param contractId id
     * @return data
     */
    @Override
    public CrmInfoNumVO num(Integer contractId) {
        CrmContract crmContract = getById(contractId);
        List<CrmField> crmFields = crmFieldService.queryFileField();
        List<String> batchIdList = new ArrayList<>();
        if (crmFields.size() > 0) {
            LambdaQueryWrapper<CrmContractData> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(CrmContractData::getValue);
            wrapper.eq(CrmContractData::getBatchId, crmContract.getBatchId());
            wrapper.in(CrmContractData::getFieldId, crmFields.stream().map(CrmField::getFieldId).collect(Collectors.toList()));
            batchIdList.addAll(crmContractDataService.listObjs(wrapper, Object::toString));
        }
        batchIdList.add(crmContract.getBatchId());
        batchIdList.addAll(crmActivityService.queryFileBatchId(crmContract.getContractId(), getLabel().getType()));
        String receivableCon = AuthUtil.getCrmAuthSql(CrmEnum.RECEIVABLES, 1);
        String returnVisitCon = AuthUtil.getCrmAuthSql(CrmEnum.RETURN_VISIT, 1);
        String invoiceCon = AuthUtil.getCrmAuthSql(CrmEnum.INVOICE, 1);
        Map<String, Object> map = new HashMap<>();
        map.put("contractId", contractId);
        map.put("receivableCon", receivableCon);
        map.put("returnVisitCon", returnVisitCon);
        map.put("invoiceCon", invoiceCon);
        CrmInfoNumVO infoNumVO = getBaseMapper().queryNum(map);
        infoNumVO.setFileCount(adminFileService.queryNum(batchIdList));
        Set<String> member = new HashSet<>();
        member.addAll(StrUtil.splitTrim(crmContract.getRoUserId(), Const.SEPARATOR));
        member.addAll(StrUtil.splitTrim(crmContract.getRwUserId(), Const.SEPARATOR));
        if (crmContract.getOwnerUserId() != null) {
            member.add(crmContract.getOwnerUserId().toString());
        }
        infoNumVO.setMemberCount(member.size());
        return infoNumVO;
    }

    /**
     * 查询文件列表
     *
     * @param contractId id
     * @return file
     */
    @Override
    public List<FileEntity> queryFileList(Integer contractId) {
        List<FileEntity> fileEntityList = new ArrayList<>();
        CrmContract crmContract = getById(contractId);
        adminFileService.queryFileList(crmContract.getBatchId()).forEach(fileEntity -> {
            fileEntity.setSource("附件上传");
            fileEntity.setReadOnly(0);
            fileEntityList.add(fileEntity);
        });
        List<CrmField> crmFields = crmFieldService.queryFileField();
        if (crmFields.size() > 0) {
            LambdaQueryWrapper<CrmContractData> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(CrmContractData::getValue);
            wrapper.eq(CrmContractData::getBatchId, crmContract.getBatchId());
            wrapper.in(CrmContractData::getFieldId, crmFields.stream().map(CrmField::getFieldId).collect(Collectors.toList()));
            List<FileEntity> data = adminFileService.queryFileList(crmContractDataService.listObjs(wrapper, Object::toString));
            data.forEach(fileEntity -> {
                fileEntity.setSource("合同详情");
                fileEntity.setReadOnly(1);
                fileEntityList.add(fileEntity);
            });
        }
        List<String> stringList = crmActivityService.queryFileBatchId(crmContract.getContractId(), getLabel().getType());
        if (stringList.size() > 0) {
            List<FileEntity> data = adminFileService.queryFileList(stringList);
            data.forEach(fileEntity -> {
                fileEntity.setSource("跟进记录");
                fileEntity.setReadOnly(1);
                fileEntityList.add(fileEntity);
            });
        }
        return fileEntityList;
    }

    @Override
    public BasePage<CrmReceivablesPlan> queryReceivablesPlanListByContractId(CrmRelationPageBO crmRelationPageBO) {
        CrmReceivablesPlanMapper mapper = (CrmReceivablesPlanMapper) crmReceivablesPlanService.getBaseMapper();
        return mapper.queryReceivablesPlanListByContractId(crmRelationPageBO.parse(), crmRelationPageBO.getContractId());
    }

    @Override
    public List<SimpleCrmEntity> querySimpleEntity(List<Integer> ids) {
        if (ids.size() == 0) {
            return new ArrayList<>();
        }
        List<CrmContract> list = query().in("contract_id", ids).list();
        return list.stream().map(crmContract -> {
            SimpleCrmEntity simpleCrmEntity = new SimpleCrmEntity();
            simpleCrmEntity.setId(crmContract.getContractId());
            simpleCrmEntity.setName(crmContract.getName());
            return simpleCrmEntity;
        }).collect(Collectors.toList());
    }

    @Override
    public String getContractName(int contractId) {
        return lambdaQuery().select(CrmContract::getName).eq(CrmContract::getContractId, contractId).oneOpt()
                .map(CrmContract::getName).orElse("");
    }


    @Override
    public void updateInformation(CrmUpdateInformationBO updateInformationBO) {
        String batchId = updateInformationBO.getBatchId();
        Integer contractId = updateInformationBO.getId();
        CrmContract contract = getById(contractId);
//        if (contract.getCheckStatus() == 8) {
//            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_CANCELLATION_ERROR);
//        }
        if (contract.getCheckStatus() == 1) {
            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_EXAMINE_PASS_ERROR);
        }
        if (contract.getCheckStatus() != 4 && contract.getCheckStatus() != 2 && contract.getCheckStatus() != 5) {
            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_EDIT_ERROR);
        }
        updateInformationBO.getList().forEach(record -> {
            CrmContract oldContract = getById(updateInformationBO.getId());
            Long oldOwnerUserId = oldContract.getOwnerUserId();
            Map<String, Object> oldContractMap = BeanUtil.beanToMap(oldContract);
            if (record.getInteger("fieldType") == 1) {
                Map<String, Object> crmContractMap = new HashMap<>(oldContractMap);
                crmContractMap.put(record.getString("fieldName"), record.get("value"));
                CrmContract crmContract = BeanUtil.mapToBean(crmContractMap, CrmContract.class, true);
                if ("money".equals(record.getString("fieldName"))) {

                    if(new BigDecimal(String.valueOf(record.get("value"))).compareTo(new BigDecimal(0.00)) <= 0 || !Optional.ofNullable(record.get("value")).isPresent()){
                        throw new CrmException(CrmCodeEnum.CRM_CONTRACT_MONEY_GT_ZERO);
                    }

                    //判断金额
                    BigDecimal oldMonery = contract.getMoney();
                    BigDecimal newMonery = crmContract.getMoney();
                    //新老 成交金额不相等
                    if (oldMonery.compareTo(newMonery) != 0) {
                        //原始已回款金额
                        BigDecimal receivedMoney = contract.getReceivedMoney();
                        if (newMonery.compareTo(receivedMoney) < 0) {
                            throw new CrmException(CrmCodeEnum.THE_MONERY_LESS_THAN_THE_RECEIVE_MONERY);
                        }
                        List<String> fieldList = Arrays.asList(new String[]{"unreceived_money","back_status","due_monery"});
                        List<CrmField> fields = crmFieldService.lambdaQuery().select(CrmField::getFieldId,CrmField::getFieldName)
                                .in(CrmField::getFieldName, fieldList).list();
                        Map<String, Integer> map = fields.stream().collect(Collectors.toMap(CrmField::getFieldName, CrmField::getFieldId));

                        if (newMonery.compareTo(receivedMoney) == 0) {
                            //更新 未回款金额
                            BigDecimal unreceivedMoney = new BigDecimal(0);
                            JSONObject unreceivedMoneyRecord = getRecord(map.get("unreceived_money"), "unreceivedMoney", "floatnumber", "未回款金额", 6, 1, String.valueOf(unreceivedMoney));
                            update().set(StrUtil.toUnderlineCase(unreceivedMoneyRecord.getString("fieldName")), unreceivedMoneyRecord.get("value")).eq("contract_id", updateInformationBO.getId()).update();
                            updateField(unreceivedMoneyRecord, contractId);
                            //更新回款状态
                            String backStatus = "已回款";
                            JSONObject backStatusRecord = getRecord(map.get("back_status"), "backStatus", "select", "回款状态", 3, 1, backStatus);
                            update().set(StrUtil.toUnderlineCase(backStatusRecord.getString("fieldName")), backStatusRecord.get("value")).eq("contract_id", updateInformationBO.getId()).update();
                            updateField(backStatusRecord, contractId);
                            //更新 应回款金额
                            BigDecimal dueMonery = newMonery;
                            JSONObject dueMoneryRecord = getRecord(map.get("due_monery"), "dueMonery", "floatnumber", "应回款金额", 6, 1, String.valueOf(dueMonery));
                            update().set(StrUtil.toUnderlineCase(dueMoneryRecord.getString("fieldName")), dueMoneryRecord.get("value")).eq("contract_id", updateInformationBO.getId()).update();
                            updateField(dueMoneryRecord, contractId);
                        } else {
                            //更新 未回款金额
                            BigDecimal unreceivedMoney = contract.getUnreceivedMoney();
                            unreceivedMoney = unreceivedMoney.add(newMonery.subtract(oldMonery));
                            JSONObject unreceivedMoneyRecord = getRecord(map.get("unreceived_money"), "unreceivedMoney", "floatnumber", "未回款金额", 6, 1, String.valueOf(unreceivedMoney));
                            update().set(StrUtil.toUnderlineCase(unreceivedMoneyRecord.getString("fieldName")), unreceivedMoneyRecord.get("value")).eq("contract_id", updateInformationBO.getId()).update();
                            updateField(unreceivedMoneyRecord, contractId);
                            //更新回款状态
                            String backStatus = "未回款";
                            JSONObject backStatusRecord = getRecord(map.get("back_status"), "backStatus", "select", "回款状态", 3, 1, backStatus);
                            update().set(StrUtil.toUnderlineCase(backStatusRecord.getString("fieldName")), backStatusRecord.get("value")).eq("contract_id", updateInformationBO.getId()).update();
                            updateField(backStatusRecord, contractId);
                            //更新 应回款金额
                            BigDecimal dueMonery = newMonery;
                            JSONObject dueMoneryRecord = getRecord(map.get("due_monery"), "dueMonery", "floatnumber", "应回款金额", 6, 1, String.valueOf(dueMonery));
                            update().set(StrUtil.toUnderlineCase(dueMoneryRecord.getString("fieldName")), dueMoneryRecord.get("value")).eq("contract_id", updateInformationBO.getId()).update();
                            updateField(dueMoneryRecord, contractId);
                        }
                    }
                }

                if("teacherId".equals(record.getString("fieldName"))){
                    String teacherName = UserCacheUtil.getUserName(record.getLong("value"));
                    if(!UserUtil.getUserId().equals(oldContract.getTeacherId())){
                        if(oldContract.getTeacherId() != null){
                            addMessage(oldContract.getName(),teacherName,oldContract.getTeacherId(),AdminMessageEnum.CRM_CONTRACT_CHANGE_TEACHER_USER.getType(),crmContract.getContractId());
                        }
                    }
                    if(record.getLong("value") != null){
                        addMessage(oldContract.getName(),teacherName,record.getLong("value"),AdminMessageEnum.CRM_CONTRACT_CHANGE_TEACHER_USER.getType(),crmContract.getContractId());
                    }
                }

                actionRecordUtil.updateRecord(oldContractMap, crmContractMap, CrmEnum.CONTRACT, crmContract.getName(), crmContract.getContractId());
                update().set(StrUtil.toUnderlineCase(record.getString("fieldName")), record.get("value")).eq("contract_id", updateInformationBO.getId()).update();
                if ("name".equals(record.getString("fieldName"))) {
                    ElasticUtil.batchUpdateEsData(elasticsearchRestTemplate.getClient(), "contract", crmContract.getContractId().toString(), crmContract.getName());
                }
            } else if (record.getInteger("fieldType") == 0 || record.getInteger("fieldType") == 2) {
                CrmContractData contractData = crmContractDataService.lambdaQuery()
                        .select(CrmContractData::getValue)
                        .eq(CrmContractData::getFieldId, record.getInteger("fieldId"))
                        .eq(CrmContractData::getBatchId, batchId).last("limit 1").one();
                String value = contractData != null ? contractData.getValue() : null;
                boolean isUpdate = false;
                if ((null == value && null == record.get("value"))) {
                    isUpdate = false;
                } else if (null != value && !value.equals(String.valueOf(record.get("value")))) {
                    isUpdate = true;
                } else if (null != record.get("value") && !String.valueOf(record.get("value")).equals(value)) {
                    isUpdate = true;
                }
                if (isUpdate) {
                    String detail = actionRecordUtil.getDetailByFormTypeAndValue(record, value);
                    actionRecordUtil.publicContentRecord(CrmEnum.CONTRACT, BehaviorEnum.UPDATE, contractId, oldContract.getName(), detail);
                    boolean bol = crmContractDataService.lambdaUpdate()
                            .set(CrmContractData::getName, record.getString("fieldName"))
                            .set(CrmContractData::getValue, record.getString("value"))
                            .eq(CrmContractData::getFieldId, record.getInteger("fieldId"))
                            .eq(CrmContractData::getBatchId, batchId).update();
                    if (!bol) {
                        CrmContractData crmContractData = new CrmContractData();
                        crmContractData.setFieldId(record.getInteger("fieldId"));
                        crmContractData.setName(record.getString("fieldName"));
                        crmContractData.setValue(record.getString("value"));
                        crmContractData.setCreateTime(new Date());
                        crmContractData.setBatchId(batchId);
                        crmContractDataService.save(crmContractData);
                    }
                }

            }
            updateField(record, contractId);
        });
    }


    public JSONObject getRecord(Integer fieldId, String fieldName, String formType, String name, Integer type, Integer fieldType, String value) {
        JSONObject object = new JSONObject();
        object.put("fieldId", fieldId);
        object.put("fieldName", fieldName);
        object.put("formType", formType);
        object.put("name", name);
        object.put("type", type);
        object.put("fieldType", fieldType);
        object.put("value", value);
        return object;
    }


    @Override
    public BasePage<JSONObject> queryListByContractId(CrmRelationPageBO crmRelationPageBO) {
        String conditions = AuthUtil.getCrmAuthSql(CrmEnum.RECEIVABLES, "rec", 1);
        return crmReceivablesService.queryListByContractId(crmRelationPageBO.parse(), crmRelationPageBO.getContractId(), conditions);
    }

    @Override
    public List<CrmReceivablesPlan> queryReceivablesPlansByContractId(Integer contractId, Integer receivablesId) {
        List<CrmReceivablesPlan> recordList = getBaseMapper().queryReceivablesPlansByContractId(contractId);
        if (receivablesId != null) {
            CrmReceivablesPlan receivables = getBaseMapper().queryReceivablesPlansByReceivablesId(receivablesId);
            if (receivables != null) {
                recordList.add(receivables);
            }
        }
        return recordList;
    }

    @Override
    public BasePage<JSONObject> queryReturnVisit(CrmRelationPageBO crmRelationPageBO) {
        List<CrmField> nameList = crmFieldService.lambdaQuery().select(CrmField::getFieldId, CrmField::getFieldName).eq(CrmField::getLabel, CrmEnum.RETURN_VISIT.getType())
                .eq(CrmField::getIsHidden, 0).ne(CrmField::getFieldType, 1).list();
        String conditions = AuthUtil.getCrmAuthSql(CrmEnum.RECEIVABLES, "a", 1);
        BasePage<JSONObject> basePage = getBaseMapper().queryReturnVisit(crmRelationPageBO.parse(), crmRelationPageBO.getContractId(), conditions, nameList);
        for (JSONObject jsonObject : basePage.getList()) {
            String ownerUserName = UserCacheUtil.getUserName(jsonObject.getLong("ownerUserId"));
            jsonObject.put("ownerUserName", ownerUserName);
        }
        return basePage;
    }

    @Override
    public void contractDiscard(Integer contractId) {
        CrmContract contract = getById(contractId);

        QueryWrapper<CrmReceivables> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("contract_id", contractId);
        queryWrapper.and(wrapper -> wrapper.eq("check_status", 1).or().eq("check_status", 3));
        List<CrmReceivables> crmReceivablesList = SpringUtils.getBean(ICrmReceivablesService.class).query().getBaseMapper().selectList(queryWrapper);

        QueryWrapper<CrmRefund> refundQueryWrapper = new QueryWrapper<>();
        refundQueryWrapper.eq("contract_id", contractId);
        refundQueryWrapper.and(wrapper -> wrapper.eq("check_status", 1).or().eq("check_status", 3));
        List<CrmRefund> crmRefundList = SpringUtils.getBean(ICrmReFundService.class).query().getBaseMapper().selectList(refundQueryWrapper);

        if (CollectionUtil.isNotEmpty(crmReceivablesList) || CollectionUtil.isNotEmpty(crmRefundList)) {
            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_JOIN_RECEIVABLES_ERROR);
        }

        actionRecordUtil.addObjectActionRecord(CrmEnum.CONTRACT, contractId, BehaviorEnum.CANCEL_EXAMINE, contract.getName());
        lambdaUpdate().set(CrmContract::getCheckStatus, 8).set(CrmContract::getUpdateTime, new Date()).eq(CrmContract::getContractId, contractId).update();
        Map<String, Object> map = new HashMap<>();
        map.put("checkStatus", 8);
        map.put("updateTime", DateUtil.formatDateTime(new Date()));
        updateField(map, Collections.singletonList(contractId));
    }

    @Override
    public List<String> endContract(CrmEventBO crmEventBO) {
        return getBaseMapper().endContract(crmEventBO);
    }

    @Override
    public List<String> receiveContract(CrmEventBO crmEventBO) {
        return getBaseMapper().receiveContract(crmEventBO);
    }

    @Override
    public BasePage<Map<String, Object>> eventContractPageList(QueryEventCrmPageBO eventCrmPageBO) {
        Long userId = eventCrmPageBO.getUserId();
        Long time = eventCrmPageBO.getTime();
        Integer type = eventCrmPageBO.getType();
        if (userId == null) {
            userId = UserUtil.getUserId();
        }
        List<Integer> contractIds;
        List<JSONObject> records = null;
        if (type == 1) {
            AdminConfigBo adminConfig = adminService.queryFirstConfigByName("expiringContractDays");
            if (adminConfig.getStatus() == 0 || ObjectUtil.isNull(adminConfig)) {
                contractIds = new ArrayList<>();
            } else {
                contractIds = getBaseMapper().endContractList(userId, new Date(time), Integer.valueOf(adminConfig.getValue()));
            }
        } else {
            records = getBaseMapper().receiveContractList(userId, new Date(time));
            contractIds = records.stream().map(record -> record.getInteger("contractId")).collect(Collectors.toList());
        }
        if (contractIds.size() == 0) {
            return new BasePage<>();
        }
        List<String> collect = contractIds.stream().map(Object::toString).collect(Collectors.toList());
        CrmSearchBO crmSearchBO = new CrmSearchBO();
        crmSearchBO.setSearchList(Collections.singletonList(new CrmSearchBO.Search("_id", "id", CrmSearchBO.FieldSearchEnum.ID, collect)));
        crmSearchBO.setLabel(CrmEnum.CONTRACT.getType());
        crmSearchBO.setPage(eventCrmPageBO.getPage());
        crmSearchBO.setLimit(eventCrmPageBO.getLimit());
        if (type == 2) {
            BasePage<Map<String, Object>> page = queryPageList(crmSearchBO);
            for (JSONObject record : records) {
                for (Map<String, Object> map : page.getList()) {
                    if (map.get("contractId").equals(record.getInteger("contractId"))) {
                        map.putAll(record.getInnerMap());
                    }
                }
            }
            return page;
        } else {
            return queryPageList(crmSearchBO);
        }
    }

    /**
     * 根据产品ID查询合同
     *
     * @param biParams 参数
     * @return data
     */
    @Override
    public BasePage<Map<String, Object>> queryListByProductId(BiParams biParams) {
        List<CrmContractProduct> products = crmContractProductService
                .lambdaQuery()
                .select(CrmContractProduct::getContractId)
                .eq(CrmContractProduct::getProductId, biParams.getTypeId()).list();
        Integer menuId = 118;
        biParams.setMenuId(menuId);
        BiTimeUtil.BiTimeEntity timeEntity = BiTimeUtil.analyzeType(biParams);

        CrmSearchBO searchBo = new CrmSearchBO();
        searchBo.setPage(biParams.getPage());
        searchBo.setLimit(biParams.getLimit());
        searchBo.setLabel(getLabel().getType());
        searchBo.setSearch(biParams.getSearch());
        searchBo.setOrder(biParams.getOrder());
        searchBo.setSortField(biParams.getSortField());
        List<String> stringList = products.stream().map(crmContractProduct -> crmContractProduct.getContractId().toString()).collect(Collectors.toList());
        List<CrmSearchBO.Search> searchList = searchBo.getSearchList();
        searchList.add(new CrmSearchBO.Search("contractId", null, CrmSearchBO.FieldSearchEnum.ID, stringList));
        List<String> userIds = timeEntity.getUserIds().stream().map(Object::toString).collect(Collectors.toList());
        searchList.add(new CrmSearchBO.Search("ownerUserId", "single_user", CrmSearchBO.FieldSearchEnum.IS, userIds));
        searchList.add(new CrmSearchBO.Search("orderDate", "date", CrmSearchBO.FieldSearchEnum.DATE, Arrays.asList(DateUtil.formatDate(timeEntity.getBeginDate()), DateUtil.formatDate(DateUtil.offsetDay(timeEntity.getEndDate(), 1)))));
        return queryPageList(searchBo);
    }

    @Override
    public String generateNo(LocalDate date) {
        String dateStr = date.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String nextNo = getBaseMapper().getNextNo(dateStr);
        if (nextNo == null) {
            return dateStr + "000001";
        }
        return nextNo;
    }

    /**
     * 大额数量
     *
     * @return
     */
    @Override
    public Integer largeAmountNum(String laiyuan, String qishu) {
        Integer num = getBaseMapper().largeAmountNum(laiyuan, qishu);
        return null != num ? num : 0;
    }

    /**
     * 大额成交量，大额成交金额
     *
     * @param laiyuan
     * @param qishu
     * @return
     */
    @Override
    public Map<String, Object> bigDealSum(String laiyuan, String qishu) {
        return getBaseMapper().bigDealSum(laiyuan, qishu);
    }

    /**
     * 根据客户Id查询合同信息
     *
     * @param customerId 客户Id
     * @return 合同信息集合
     */
    @Override
    public String queryContractByCustomerId(Integer customerId) {
        return getBaseMapper().queryContractByCustomerId(customerId);
    }

    @Override
    public CrmContract queryContractById(@Param("contractId") Integer contractId) {
        return getBaseMapper().queryContractById(contractId);
    }

    @Override
    public CrmContract queryContractByNum(String num) {
        return getBaseMapper().queryContractByNum(num);
    }

    /**
     * 领取合同
     *
     * @param poolChangeUserBO
     */
    @Override
    public void changeUser(CrmBillOrderPoolChangeUserBO poolChangeUserBO) {
        if (!Optional.ofNullable(poolChangeUserBO.getCustomerId()).isPresent() || !Optional.ofNullable(poolChangeUserBO.getPhone()).isPresent()) {
            throw new CrmException(CrmCodeEnum.CRM_ERROR_PARAMETER_REQUIRED);
        }

        if (poolChangeUserBO.getIds().size() == 0) {
            return;
        }

        QueryWrapper<BillCrmOrderPool> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        BillCrmOrderPool orderPool = crmOrderPoolService.getBaseMapper().selectOne(queryWrapper);
        List<String> deptIds = Arrays.asList(orderPool.getMemberDeptId().split(","));

        List<Integer> allDeptIds = new ArrayList<>();
        for(String deptId : deptIds){
            allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(Integer.valueOf(deptId)));
            allDeptIds.add(Integer.valueOf(deptId));
        }

        if((!allDeptIds.contains(UserUtil.getUser().getDeptId())) && (!UserUtil.isAdmin())){
            throw new CrmException(CrmCodeEnum.CRM_NO_AUTH_RECEIVE);
        }

        QueryWrapper<BillCrmStudentPool> studentPoolQueryWrapper = new QueryWrapper<BillCrmStudentPool>();
        studentPoolQueryWrapper.eq("status", 1);
        BillCrmStudentPool studentPool = crmStudentPoolService.getBaseMapper().selectOne(studentPoolQueryWrapper);

        if(CollectionUtil.isNotEmpty(poolChangeUserBO.getIds())){
            for(int i = 0;i < poolChangeUserBO.getIds().size();i++){
                CrmContract contract = getById(poolChangeUserBO.getIds().get(i));
                if (!contract.getPhone().equals(poolChangeUserBO.getPhone())) {
                    throw new CrmException(CrmCodeEnum.CRM_ORDER_POLL_PHONE);
                }
                if(ObjectUtil.isNotEmpty(contract.getOwnerUserId())){
                    throw new CrmException(CrmCodeEnum.ORDER_IS_RECEIVE);
                }
                SpringUtils.getBean(ICrmContractService.class).lingQuOrder(poolChangeUserBO.getIds().get(i),poolChangeUserBO,studentPool);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void lingQuOrder(Integer id, CrmBillOrderPoolChangeUserBO poolChangeUserBO, BillCrmStudentPool studentPool){
        String key = Constants.RECEIVE_ORDER + id;
        String value = UUID.randomUUID().toString();

        //加锁
        boolean b = redisCache.lock(key, value, 10, TimeUnit.SECONDS);
        if (!b) {
            throw new CrmException(CrmCodeEnum.BUSINESS_LOCK_DATA);
        }
        try {
            Long userId = UserUtil.getUserId();
            String phone = poolChangeUserBO.getPhone();

            CrmContract contract = getById(id);
            if (!contract.getPhone().equals(phone)) {
                throw new CrmException(CrmCodeEnum.CRM_ORDER_POLL_PHONE);
            }
            if(ObjectUtil.isNotEmpty(contract.getOwnerUserId())){
                throw new CrmException(CrmCodeEnum.ORDER_IS_RECEIVE);
            }

            QueryWrapper<CrmContract> zdQueryWrapper = new QueryWrapper<>();
            zdQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            zdQueryWrapper.in("check_status", Arrays.asList(1,3));
            zdQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_账单合同.getMsg());
            Integer zdCount = baseMapper.selectCount(zdQueryWrapper);
            if(zdCount > 0){
                // 您已经有账单合同，不能重复领取。
                throw new CrmException(CrmCodeEnum.CRM_CUSTOMER_HAVE_ZD_CONTRACT);
            }

            QueryWrapper<CrmContract> qeQueryWrapper = new QueryWrapper<>();
            qeQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            qeQueryWrapper.in("check_status", Arrays.asList(1,3));
            qeQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_全款合同.getMsg());
            Integer qeCount = baseMapper.selectCount(qeQueryWrapper);
            if(qeCount > 0){
                // 您已经有全款合同，不能重复领取。
                throw new CrmException(CrmCodeEnum.CRM_CUSTOMER_HAVE_QE_CONTRACT);
            }

            QueryWrapper<CrmContract> sfkQueryWrapper = new QueryWrapper<>();
            sfkQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            sfkQueryWrapper.in("check_status", Arrays.asList(1,3));
            sfkQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_首付款合同.getMsg());
            List<CrmContract> crmContracts1 = baseMapper.selectList(sfkQueryWrapper);
            if(CollectionUtil.isNotEmpty(crmContracts1)){
                CrmContract crmContract = crmContracts1.get(0);
                if(crmContract.getCheckStatus() != 1){
                    // buneng
                    throw new CrmException(CrmCodeEnum.ORDER_SFK_NO_CHECK_NOT_RECEIVE);
                }

                QueryWrapper<CrmReceivables> receivablesQueryWrapper = new QueryWrapper<>();
                receivablesQueryWrapper.eq("contract_id", crmContract.getContractId());
                receivablesQueryWrapper.notIn("check_status", Arrays.asList(1,7));
                Integer checkNoCount = crmReceivablesService.getBaseMapper().selectCount(receivablesQueryWrapper);

                QueryWrapper<CrmReceivables> receivablesQueryWrapper1 = new QueryWrapper<>();
                receivablesQueryWrapper1.eq("contract_id", crmContract.getContractId());
                receivablesQueryWrapper1.eq("check_status", 1);
                Integer checkOkCount = crmReceivablesService.getBaseMapper().selectCount(receivablesQueryWrapper1);

                if(checkNoCount > 0 && checkOkCount == 0){
                    throw new CrmException(CrmCodeEnum.ORDER_SFK_NO_CHECK_NOT_RECEIVE);
                }
            }

            QueryWrapper<CrmContract> txbkQueryWrapper = new QueryWrapper<>();
            txbkQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            txbkQueryWrapper.in("check_status", Arrays.asList(1,3));
            txbkQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_线下合同.getMsg());
            Integer txbkCount = baseMapper.selectCount(txbkQueryWrapper);
            if(txbkCount > 0){
                // 您已经有线下合同，不能重复领取。
                throw new CrmException(CrmCodeEnum.CRM_CUSTOMER_HAVE_TXBK_CONTRACT);
            }

            //更新学员还款状态
            CrmCustomer crmCustomer = crmCustomerService.getById(poolChangeUserBO.getCustomerId());
            crmCustomer.setRepaymentStatus(contract.getRepaymentStatus());
            crmCustomer.setVipDealStatus(contract.getDealStatus());
            crmCustomer.setVipDealTime(contract.getDealTime());
            if (contract.getRepaymentStatus().equals(CrmBusinessConstEnum.还款状态_已退学.getMsg())) {
                crmCustomer.setStudentStatus(0);
            } else {
                crmCustomer.setStudentStatus(1);
            }
            crmCustomerService.updateById(crmCustomer);

            //新增VIP学员
            CrmStudent crmStudent = BeanUtil.copyProperties(crmCustomer, CrmStudent.class);
            if(StringUtils.isEmpty(crmStudent.getTelephone())){
                crmStudent.setTelephone(phone);
            }
            //设置VIP学员池
            crmStudent.setStudentPoolId(studentPool.getStudentPoolId());
            crmStudent.setCustomerLabel("正常学员");
            crmStudent.setRiskLabel(CrmBusinessConstEnum.风险提示_正常.getMsg());
            crmStudent.setStudentStatus(Const.ALREADY_ENTRANCE);
            crmStudentService.save(crmStudent);

            //转移活动数据
            List<CrmActivity> crmActivityList = crmActivityService.lambdaQuery().eq(CrmActivity::getActivityType, 2).eq(CrmActivity::getType, 1).eq(CrmActivity::getActivityTypeId, poolChangeUserBO.getCustomerId()).list();
            if (crmActivityList.size() != 0) {
                crmActivityList.forEach(crmActivity -> {
                    List<FileEntity> leadsRecordFiles = adminFileService.queryFileList(crmActivity.getBatchId());
                    String studentRecordBatchId = IdUtil.simpleUUID();
                    List<String> fileIds = leadsRecordFiles.stream().map(FileEntity::getFileId).collect(Collectors.toList());
                    crmActivity.setBatchId(studentRecordBatchId);
                    crmActivity.setActivityId(null);
                    crmActivity.setActivityType(CrmEnum.STUDENT.getType());
                    crmActivity.setActivityTypeId(crmStudent.getStudentId());
                    if(CollectionUtil.isNotEmpty(fileIds)){
                        adminFileService.saveBatchFileEntity(fileIds, studentRecordBatchId);
                    }
                });
                crmActivityService.saveBatch(crmActivityList, 100);
            }

            QueryWrapper<CrmReceivables> receivablesWrapper = new QueryWrapper<>();
            receivablesWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            receivablesWrapper.and(wrapper -> wrapper.eq("check_status", 1).or().eq("check_status", 3));
            List<CrmReceivables> crmReceivablesList = crmReceivablesService.query().getBaseMapper().selectList(receivablesWrapper);

            //查询客户下所有合同
            QueryWrapper<CrmContract> crmContractWrapper = new QueryWrapper<>();
            crmContractWrapper.eq("customer_id",poolChangeUserBO.getCustomerId());
            crmContractWrapper.and(wrapper -> wrapper.eq("check_status",1));
            List<CrmContract> crmContractList = list(crmContractWrapper);

            //转移操作记录
            List<Integer> contractIds = crmContractList.stream().map(CrmContract::getContractId).collect(Collectors.toList());
            List<Integer> receivablesIdList = crmReceivablesList.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(contractIds) && CollectionUtil.isNotEmpty(receivablesIdList)){
                List<CrmActionRecord> crmActionRecordList = crmActionRecordService.lambdaQuery().eq(CrmActionRecord::getActionId, poolChangeUserBO.getCustomerId()).eq(CrmActionRecord::getTypes, 2).list();
//                List<CrmActionRecord> contractActionRecordList = crmActionRecordService.lambdaQuery().in(CrmActionRecord::getActionId, contractIds).eq(CrmActionRecord::getTypes, 6).list();
//                List<CrmActionRecord> receivablesActionRecordList = crmActionRecordService.lambdaQuery().in(CrmActionRecord::getActionId, receivablesIdList).eq(CrmActionRecord::getTypes, 7).list();
//                crmActionRecordList.addAll(contractActionRecordList);
//                crmActionRecordList.addAll(receivablesActionRecordList);
                crmActionRecordList.forEach(crmActionRecord -> {
                    crmActionRecord.setId(null);
                    if(CrmEnum.CUSTOMER.getType().equals(crmActionRecord.getTypes())){
                        crmActionRecord.setTypes(CrmEnum.STUDENT.getType());
                        crmActionRecord.setActionId(crmStudent.getStudentId());
                    }
                });
                crmActionRecordService.saveBatch(crmActionRecordList, 500);
            }


            contract.setStudentId(crmStudent.getStudentId());
            contract.setCreateUserId(userId);
            contract.setOwnerUserId(userId);
            contract.setBillTime(DateUtils.getNowDate());
            contract.setUpdateTime(DateUtils.getNowDate());
            contract.setCustomerId(poolChangeUserBO.getCustomerId());
            contract.setTeacherId(crmCustomer.getTeacherId());
            contract.setSource(crmCustomer.getSource());
            contract.setTrainingPeriods(crmCustomer.getTrainingPeriods());
            contract.setLeadsFormTime(crmCustomer.getLeadsFormTime());
            update(contract, new UpdateWrapper<CrmContract>().lambda().set(CrmContract::getOwnerOrderPool, null).eq(CrmContract::getContractId, contract.getContractId()));
//            actionRecordUtil.addConversionRecord(id, CrmEnum.CONTRACT, changOwnerUserBO.getOwnerUserId(), contract.getName());

            // 变更账单外的合同VIP学员Id
            QueryWrapper<CrmContract> contractQueryWrapper = new QueryWrapper<>();
            contractQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            contractQueryWrapper.in("check_status", Arrays.asList(1,3));
            contractQueryWrapper.ne("contract_id", id);
            List<CrmContract> crmContracts = list(contractQueryWrapper);
            crmContracts.forEach(crmContract -> {
                update(new UpdateWrapper<CrmContract>().lambda().set(CrmContract::getStudentId, crmStudent.getStudentId()).eq(CrmContract::getContractId, crmContract.getContractId()));

                Integer contractId = crmContract.getContractId();
                QueryWrapper<CrmReceivables> query = new QueryWrapper();
                query.eq("contract_id", contractId);
                query.ne("check_status", 7);
                List<CrmReceivables> receivablesList = crmReceivablesService.list(query);
                if(CollectionUtil.isEmpty(receivablesList)){
                    // 该学员下存在没有回款的合同，暂不能领取
                    throw new CrmException(CrmCodeEnum.CRM_CONTRACT_RECEIVE_ERROR);
                }
                List<Integer> receivablesIds = receivablesList.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());
                crmReceivablesService.update(new UpdateWrapper<CrmReceivables>().lambda().set(CrmReceivables::getStudentId, crmStudent.getStudentId()).in(CrmReceivables::getReceivablesId, receivablesIds));
            });

            Integer contractId = contract.getContractId();
            QueryWrapper<CrmReceivables> query = new QueryWrapper();
            query.eq("contract_id", contractId);
            query.ne("check_status", 7);
            List<CrmReceivables> receivablesList = crmReceivablesService.list(query);
            receivablesList.forEach(crmReceivables -> {
                crmReceivables.setStudentId(crmStudent.getStudentId());
                crmReceivables.setCreateUserId(userId);
                crmReceivables.setOwnerUserId(userId);
                crmReceivables.setUpdateTime(DateUtils.getNowDate());
                crmReceivables.setCustomerId(poolChangeUserBO.getCustomerId());
                crmReceivables.setTeacherId(crmCustomer.getTeacherId());
                crmReceivables.setOwnerDeptId(String.valueOf(UserCacheUtil.getUserInfo(userId).getDeptId()));
                crmReceivables.setSource(crmCustomer.getSource());
                crmReceivables.setTrainingPeriods(crmCustomer.getTrainingPeriods());
                crmReceivables.setLeadsFormTime(crmCustomer.getLeadsFormTime());
                crmReceivablesService.update(crmReceivables, new UpdateWrapper<CrmReceivables>().lambda().set(CrmReceivables::getOwnerOrderPool, null).eq(CrmReceivables::getReceivablesId, crmReceivables.getReceivablesId()));
            });

            CrmLeads leads = crmLeadsService.queryLeadsDataBySerialNumber(crmCustomer.getSerialNumber());
            leads.setVipDealStatus(contract.getDealStatus());
            leads.setVipDealTime(contract.getDealTime());
            crmLeadsService.updateById(leads);

            Map<String, Object> mapLeads = new HashMap<>();
            mapLeads.put("vipDealStatus", contract.getDealStatus());
            mapLeads.put("vipDealTime", DateUtil.formatDateTime(contract.getDealTime()));
            ElasticUtil.updateField(elasticsearchRestTemplate, mapLeads, leads.getLeadsId(), CrmEnum.LEADS.getIndex());

            //修改学员还款状态
            Map<String, Object> mapCustomer = new HashMap<>();
            mapCustomer.put("repaymentStatus", contract.getRepaymentStatus());
            mapCustomer.put("vipDealStatus", contract.getDealStatus());
            mapCustomer.put("vipDealTime", DateUtil.formatDateTime(contract.getDealTime()));
            if (contract.getRepaymentStatus().equals(CrmBusinessConstEnum.还款状态_已退学.getMsg())) {
                mapCustomer.put("studentStatus", 0);
            } else {
                mapCustomer.put("studentStatus", 1);
            }
            ElasticUtil.updateField(elasticsearchRestTemplate, mapCustomer, crmCustomer.getCustomerId(), CrmEnum.CUSTOMER.getIndex());

            String teacherName = UserCacheUtil.getUserName(crmCustomer.getTeacherId());
            String ownerUserName = UserCacheUtil.getUserName(userId);
            //新增vip学员es
            CrmModelSaveBO studentModel = new CrmModelSaveBO();
            Map<String, Object> studentMap = BeanUtil.beanToMap(crmStudent);
            studentMap.put("repaymentStatus", contract.getRepaymentStatus());
            studentMap.put("receiveTime",DateUtil.formatDateTime(crmStudent.getReceiveTime()));
            studentMap.put("drawTime",DateUtil.formatDateTime(crmStudent.getDrawTime()));
            studentMap.put("vipDealTime", DateUtil.formatDateTime(contract.getDealTime()));
            studentMap.put("createTime", DateUtil.formatDateTime(crmStudent.getCreateTime()));
            studentMap.put("updateTime", DateUtil.formatDateTime(crmStudent.getUpdateTime()));
            studentMap.put("teacherName", teacherName);
            studentMap.put("ownerUserName", ownerUserName);
            studentModel.setEntity(studentMap);
            savePageByLable(studentModel, crmStudent.getStudentId(), false, CrmEnum.STUDENT.getType());

            //修改合同es
            Map<String, Object> map = new HashMap<>();
            map.put("createUserId", userId);
            map.put("ownerUserId", userId);
            map.put("billTime", DateUtils.getTime());
            map.put("updateTime", DateUtils.getTime());
            map.put("ownerOrderPool", null);
            map.put("teacherId", crmCustomer.getTeacherId());
            map.put("teacherName", teacherName);
            map.put("source", crmCustomer.getSource());
            map.put("trainingPeriods", crmCustomer.getTrainingPeriods());
            map.put("studentId", crmStudent.getStudentId());
            map.put("customerId",poolChangeUserBO.getCustomerId());
            map.put("customerName",crmCustomer.getCustomerName());
            map.put("leadsFormTime",DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,crmCustomer.getLeadsFormTime()));
            ElasticUtil.updateField(elasticsearchRestTemplate, map, id, CrmEnum.CONTRACT.getIndex());

            // 变更账单外的合同VIP学员Id
            crmContracts.forEach(otherContract -> {
                Map<String, Object> otherContractMap = new HashMap<>();
                otherContractMap.put("studentId", crmStudent.getStudentId());
                ElasticUtil.updateField(elasticsearchRestTemplate, otherContractMap, otherContract.getContractId(), CrmEnum.CONTRACT.getIndex());

                QueryWrapper<CrmReceivables> wrapper = new QueryWrapper();
                wrapper.eq("contract_id", otherContract.getContractId());
                wrapper.ne("check_status", 7);
                List<CrmReceivables> receivablesByContract = crmReceivablesService.list(wrapper);
                List<Integer> receivablesIds = receivablesByContract.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());

                ElasticUtil.updateField(elasticsearchRestTemplate,"studentId",crmStudent.getStudentId(),receivablesIds, CrmEnum.RECEIVABLES.getIndex());
            });

            //修改回款es
            receivablesList.forEach(crmReceivables -> {
                Map<String, Object> mapReceivables = new HashMap<>();
                mapReceivables.put("createUserId", userId);
                mapReceivables.put("ownerUserId", userId);
                mapReceivables.put("updateTime", DateUtils.getTime());
                mapReceivables.put("customerId", poolChangeUserBO.getCustomerId());
                mapReceivables.put("ownerOrderPool", null);
                mapReceivables.put("teacherId", crmCustomer.getTeacherId());
                mapReceivables.put("teacherName", teacherName);
                mapReceivables.put("ownerDeptId", String.valueOf(UserCacheUtil.getUserInfo(userId).getDeptId()));
                mapReceivables.put("source", crmCustomer.getSource());
                mapReceivables.put("trainingPeriods", crmCustomer.getTrainingPeriods());
                mapReceivables.put("studentId", crmStudent.getStudentId());
                mapReceivables.put("customerName",crmCustomer.getCustomerName());
                mapReceivables.put("leadsFormTime",DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,crmCustomer.getLeadsFormTime()));
                ElasticUtil.updateField(elasticsearchRestTemplate, mapReceivables, crmReceivables.getReceivablesId(), CrmEnum.RECEIVABLES.getIndex());
            });

        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            redisCache.unlock(key, value);
        }
    }


    public static boolean isContains(List<String> oneList,List<String> otherList){
        for(String other : otherList){
            if(oneList.contains(other)){
                return true;
            }
        }
        return false;
    }

    /*
    分配账单
     */
    @Override
    public void allocationOrderPoolUser(CrmBillOrderPoolChangeUserBO poolChangeUserBO) {
        if ((!Optional.ofNullable(poolChangeUserBO.getCustomerId()).isPresent()) || (!Optional.ofNullable(poolChangeUserBO.getOwnerUserId()).isPresent())) {
            throw new CrmException(CrmCodeEnum.CRM_ERROR_PARAMETER_REQUIRED);
        }
        Long userId = UserUtil.getUserId();

        if (poolChangeUserBO.getIds().size() == 0) {
            return;
        }

        QueryWrapper<BillCrmOrderPool> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        BillCrmOrderPool orderPool = crmOrderPoolService.getBaseMapper().selectOne(queryWrapper);
        List<String> roleIds = Arrays.asList(orderPool.getMemberUserId().split(","));
        List<String> deptIds = Arrays.asList(orderPool.getMemberDeptId().split(","));

        List<Integer> roles = UserUtil.getUser().getRoles();
        List<String> roleIdsToStr = roles.stream().map(Object::toString).collect(Collectors.toList());

        List<Integer> allDeptIds = new ArrayList<>();
        for(String deptId : deptIds){
            allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(Integer.valueOf(deptId)));
            allDeptIds.add(Integer.valueOf(deptId));
        }

        if(((!allDeptIds.contains(UserUtil.getUser().getDeptId())) && (!UserUtil.isAdmin())) || ((!isContains(roleIds, roleIdsToStr)) && (!UserUtil.isAdmin()))){
            throw new CrmException(CrmCodeEnum.CRM_NO_AUTH_DISTRIBUTION);
        }

        QueryWrapper<BillCrmStudentPool> studentPoolQueryWrapper = new QueryWrapper<BillCrmStudentPool>();
        studentPoolQueryWrapper.eq("status", 1);
        BillCrmStudentPool studentPool = crmStudentPoolService.getBaseMapper().selectOne(studentPoolQueryWrapper);

        if(CollectionUtil.isNotEmpty(poolChangeUserBO.getIds())){
            for(int i = 0;i < poolChangeUserBO.getIds().size();i++){
                CrmContract contract = getById(poolChangeUserBO.getIds().get(i));
                if(ObjectUtil.isNotEmpty(contract.getOwnerUserId())){
                    throw new CrmException(CrmCodeEnum.ORDER_IS_RECEIVE);
                }
                SpringUtils.getBean(ICrmContractService.class).distributionOrder(poolChangeUserBO.getIds().get(i),poolChangeUserBO,studentPool);
            }
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public void distributionOrder(Integer id, CrmBillOrderPoolChangeUserBO poolChangeUserBO, BillCrmStudentPool studentPool){
        String key = Constants.RECEIVE_ORDER + id;
        String value = UUID.randomUUID().toString();

        //加锁
        boolean b = redisCache.lock(key, value, 10, TimeUnit.SECONDS);
        if (!b) {
            throw new CrmException(CrmCodeEnum.BUSINESS_LOCK_DATA);
        }

        try {

            String ownerUserName = UserCacheUtil.getUserName(poolChangeUserBO.getOwnerUserId());
            String phone = poolChangeUserBO.getPhone();

            CrmContract contract = getById(id);
            if(ObjectUtil.isNotEmpty(contract.getOwnerUserId())){
                throw new CrmException(CrmCodeEnum.ORDER_IS_RECEIVE);
            }

            QueryWrapper<CrmContract> zdQueryWrapper = new QueryWrapper<>();
            zdQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            zdQueryWrapper.in("check_status", Arrays.asList(1,3));
            zdQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_账单合同.getMsg());
            Integer zdCount = baseMapper.selectCount(zdQueryWrapper);
            if(zdCount > 0){
                // 您已经有账单合同，不能重复领取。
                throw new CrmException(CrmCodeEnum.CRM_CUSTOMER_HAVE_ZD_CONTRACT);
            }

            QueryWrapper<CrmContract> qeQueryWrapper = new QueryWrapper<>();
            qeQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            qeQueryWrapper.in("check_status", Arrays.asList(1,3));
            qeQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_全款合同.getMsg());
            Integer qeCount = baseMapper.selectCount(qeQueryWrapper);
            if(qeCount > 0){
                // 您已经有全款合同，不能重复领取。
                throw new CrmException(CrmCodeEnum.CRM_CUSTOMER_HAVE_QE_CONTRACT);
            }

            QueryWrapper<CrmContract> sfkQueryWrapper = new QueryWrapper<>();
            sfkQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            sfkQueryWrapper.in("check_status", Arrays.asList(1,3));
            sfkQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_首付款合同.getMsg());
            List<CrmContract> crmContracts1 = baseMapper.selectList(sfkQueryWrapper);
            if(CollectionUtil.isNotEmpty(crmContracts1)){
                CrmContract crmContract = crmContracts1.get(0);
                if(crmContract.getCheckStatus() != 1){
                    // buneng
                    throw new CrmException(CrmCodeEnum.ORDER_SFK_NO_CHECK_NOT_RECEIVE);
                }

                QueryWrapper<CrmReceivables> receivablesQueryWrapper = new QueryWrapper<>();
                receivablesQueryWrapper.eq("contract_id", crmContract.getContractId());
//                receivablesQueryWrapper.ne("check_status", 7);
                receivablesQueryWrapper.notIn("check_status", Arrays.asList(1,7));
                Integer checkNoCount = crmReceivablesService.getBaseMapper().selectCount(receivablesQueryWrapper);

                QueryWrapper<CrmReceivables> receivablesQueryWrapper1 = new QueryWrapper<>();
                receivablesQueryWrapper1.eq("contract_id", crmContract.getContractId());
                receivablesQueryWrapper1.eq("check_status", 1);
                Integer checkOkCount = crmReceivablesService.getBaseMapper().selectCount(receivablesQueryWrapper1);

                if(checkNoCount > 0 && checkOkCount == 0){
                    throw new CrmException(CrmCodeEnum.ORDER_SFK_NO_CHECK_NOT_RECEIVE);
                }
            }

            QueryWrapper<CrmContract> txbkQueryWrapper = new QueryWrapper<>();
            txbkQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            txbkQueryWrapper.in("check_status", Arrays.asList(1,3));
            txbkQueryWrapper.eq("contract_category", CrmBusinessConstEnum.账单类别_线下合同.getMsg());
            Integer txbkCount = baseMapper.selectCount(txbkQueryWrapper);
            if(txbkCount > 0){
                // 您已经有线下合同，不能重复领取。
                throw new CrmException(CrmCodeEnum.CRM_CUSTOMER_HAVE_TXBK_CONTRACT);
            }

            //更新学员还款状态
            CrmCustomer crmCustomer = crmCustomerService.getById(poolChangeUserBO.getCustomerId());
            crmCustomer.setRepaymentStatus(contract.getRepaymentStatus());
            crmCustomer.setVipDealStatus(contract.getDealStatus());
            crmCustomer.setVipDealTime(contract.getDealTime());
            if (contract.getRepaymentStatus().equals(CrmBusinessConstEnum.还款状态_已退学.getMsg())) {
                crmCustomer.setStudentStatus(0);
            } else {
                crmCustomer.setStudentStatus(1);
            }
            crmCustomerService.updateById(crmCustomer);
            //新增VIP学员
            CrmStudent crmStudent = BeanUtil.copyProperties(crmCustomer, CrmStudent.class);
            if(StringUtils.isEmpty(crmStudent.getTelephone())){
                crmStudent.setTelephone(contract.getPhone());
            }
            crmStudent.setStudentPoolId(studentPool.getStudentPoolId());
            crmStudent.setCustomerLabel("正常学员");
            crmStudent.setRiskLabel(CrmBusinessConstEnum.风险提示_正常.getMsg());
            crmStudent.setStudentStatus(Const.ALREADY_ENTRANCE);
            crmStudentService.save(crmStudent);

            //转移活动数据
            List<CrmActivity> crmActivityList = crmActivityService.lambdaQuery().eq(CrmActivity::getActivityType, 2).eq(CrmActivity::getType, 1).eq(CrmActivity::getActivityTypeId, poolChangeUserBO.getCustomerId()).list();
            if (crmActivityList.size() != 0) {
                crmActivityList.forEach(crmActivity -> {
                    List<FileEntity> leadsRecordFiles = adminFileService.queryFileList(crmActivity.getBatchId());
                    String studentRecordBatchId = IdUtil.simpleUUID();
                    List<String> fileIds = leadsRecordFiles.stream().map(FileEntity::getFileId).collect(Collectors.toList());
                    crmActivity.setBatchId(studentRecordBatchId);
                    crmActivity.setActivityId(null);
                    crmActivity.setActivityType(CrmEnum.STUDENT.getType());
                    crmActivity.setActivityTypeId(crmStudent.getStudentId());
                    if(CollectionUtil.isNotEmpty(fileIds)){
                        adminFileService.saveBatchFileEntity(fileIds, studentRecordBatchId);
                    }
                });
                crmActivityService.saveBatch(crmActivityList, 100);
            }

            QueryWrapper<CrmReceivables> receivablesWrapper = new QueryWrapper<>();
            receivablesWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            receivablesWrapper.and(wrapper -> wrapper.eq("check_status", 1).or().eq("check_status", 3));
            List<CrmReceivables> crmReceivablesList = crmReceivablesService.query().getBaseMapper().selectList(receivablesWrapper);

            //查询客户下所有合同
            QueryWrapper<CrmContract> crmContractWrapper = new QueryWrapper<>();
            crmContractWrapper.eq("customer_id",poolChangeUserBO.getCustomerId());
            crmContractWrapper.and(wrapper -> wrapper.eq("check_status",1));
            List<CrmContract> crmContractList = list(crmContractWrapper);

            //转移操作记录
            List<Integer> contractIds = crmContractList.stream().map(CrmContract::getContractId).collect(Collectors.toList());
            List<Integer> receivablesIdList = crmReceivablesList.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(contractIds) && CollectionUtil.isNotEmpty(receivablesIdList)){
                List<CrmActionRecord> crmActionRecordList = crmActionRecordService.lambdaQuery().eq(CrmActionRecord::getActionId, poolChangeUserBO.getCustomerId()).eq(CrmActionRecord::getTypes, 2).list();
//                List<CrmActionRecord> contractActionRecordList = crmActionRecordService.lambdaQuery().in(CrmActionRecord::getActionId, contractIds).eq(CrmActionRecord::getTypes, 6).list();
//                List<CrmActionRecord> receivablesActionRecordList = crmActionRecordService.lambdaQuery().in(CrmActionRecord::getActionId, receivablesIdList).eq(CrmActionRecord::getTypes, 7).list();
//                crmActionRecordList.addAll(contractActionRecordList);
//                crmActionRecordList.addAll(receivablesActionRecordList);
                crmActionRecordList.forEach(crmActionRecord -> {
                    crmActionRecord.setId(null);
                    if(CrmEnum.CUSTOMER.getType().equals(crmActionRecord.getTypes())){
                        crmActionRecord.setTypes(CrmEnum.STUDENT.getType());
                        crmActionRecord.setActionId(crmStudent.getStudentId());
                    }
                });
                crmActionRecordService.saveBatch(crmActionRecordList, 500);
            }

            contract.setStudentId(crmStudent.getStudentId());
            contract.setCreateUserId(poolChangeUserBO.getOwnerUserId());
            contract.setOwnerUserId(poolChangeUserBO.getOwnerUserId());
            contract.setBillTime(DateUtils.getNowDate());
            contract.setUpdateTime(DateUtils.getNowDate());
            contract.setCustomerId(poolChangeUserBO.getCustomerId());
            contract.setTeacherId(crmCustomer.getTeacherId());
            contract.setSource(crmCustomer.getSource());
            contract.setTrainingPeriods(crmCustomer.getTrainingPeriods());
            contract.setLeadsFormTime(crmCustomer.getLeadsFormTime());
            update(contract, new UpdateWrapper<CrmContract>().lambda().set(CrmContract::getOwnerOrderPool, null).eq(CrmContract::getContractId, contract.getContractId()));
//            actionRecordUtil.addConversionRecord(id, CrmEnum.CONTRACT, changOwnerUserBO.getOwnerUserId(), contract.getName());

            // 变更账单外的合同VIP学员Id
            QueryWrapper<CrmContract> contractQueryWrapper = new QueryWrapper<>();
            contractQueryWrapper.eq("customer_id", poolChangeUserBO.getCustomerId());
            contractQueryWrapper.in("check_status", Arrays.asList(1,3));
            contractQueryWrapper.ne("contract_id", id);
            List<CrmContract> crmContracts = list(contractQueryWrapper);
            crmContracts.forEach(crmContract -> {
                update(new UpdateWrapper<CrmContract>().lambda().set(CrmContract::getStudentId, crmStudent.getStudentId()).eq(CrmContract::getContractId, crmContract.getContractId()));

                Integer contractId = crmContract.getContractId();
                QueryWrapper<CrmReceivables> query = new QueryWrapper();
                query.eq("contract_id", contractId);
                query.ne("check_status", 7);
                List<CrmReceivables> receivablesList = crmReceivablesService.list(query);

                if(CollectionUtil.isEmpty(receivablesList)){
                    // 该学员下存在没有回款的合同，暂不能领取
                    throw new CrmException(CrmCodeEnum.CRM_CONTRACT_RECEIVE_ERROR);
                }

                List<Integer> receivablesIds = receivablesList.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());
                crmReceivablesService.update(new UpdateWrapper<CrmReceivables>().lambda().set(CrmReceivables::getStudentId, crmStudent.getStudentId()).in(CrmReceivables::getReceivablesId, receivablesIds));
            });

            Integer contractId = contract.getContractId();
            QueryWrapper<CrmReceivables> query = new QueryWrapper();
            query.eq("contract_id", contractId);
            query.ne("check_status", 7);
            List<CrmReceivables> receivablesList = crmReceivablesService.list(query);
            receivablesList.forEach(crmReceivables -> {
                crmReceivables.setStudentId(crmStudent.getStudentId());
                crmReceivables.setCreateUserId(poolChangeUserBO.getOwnerUserId());
                crmReceivables.setOwnerUserId(poolChangeUserBO.getOwnerUserId());
                crmReceivables.setUpdateTime(DateUtils.getNowDate());
                crmReceivables.setCustomerId(poolChangeUserBO.getCustomerId());
                crmReceivables.setTeacherId(crmCustomer.getTeacherId());
                crmReceivables.setOwnerDeptId(String.valueOf(UserCacheUtil.getUserInfo(poolChangeUserBO.getOwnerUserId()).getDeptId()));
                crmReceivables.setSource(crmCustomer.getSource());
                crmReceivables.setTrainingPeriods(crmCustomer.getTrainingPeriods());
                crmReceivables.setLeadsFormTime(crmCustomer.getLeadsFormTime());
                crmReceivablesService.update(crmReceivables, new UpdateWrapper<CrmReceivables>().lambda().set(CrmReceivables::getOwnerOrderPool, null).eq(CrmReceivables::getReceivablesId, crmReceivables.getReceivablesId()));
            });

            CrmLeads leads = crmLeadsService.queryLeadsDataBySerialNumber(crmCustomer.getSerialNumber());
            leads.setVipDealStatus(contract.getDealStatus());
            leads.setVipDealTime(contract.getDealTime());
            crmLeadsService.updateById(leads);

            Map<String, Object> mapLeads = new HashMap<>();
            mapLeads.put("vipDealStatus", contract.getDealStatus());
            mapLeads.put("vipDealTime", DateUtil.formatDateTime(contract.getDealTime()));
            ElasticUtil.updateField(elasticsearchRestTemplate, mapLeads, leads.getLeadsId(), CrmEnum.LEADS.getIndex());

            //修改学员还款状态
            Map<String, Object> mapCustomer = new HashMap<>();
            mapCustomer.put("repaymentStatus", contract.getRepaymentStatus());
            mapCustomer.put("vipDealStatus", contract.getDealStatus());
            mapCustomer.put("vipDealTime", DateUtil.formatDateTime(contract.getDealTime()));
            if (contract.getRepaymentStatus().equals(CrmBusinessConstEnum.还款状态_已退学.getMsg())) {
                mapCustomer.put("studentStatus", 0);
            } else {
                mapCustomer.put("studentStatus", 1);
            }
            ElasticUtil.updateField(elasticsearchRestTemplate, mapCustomer, crmCustomer.getCustomerId(), CrmEnum.CUSTOMER.getIndex());

            String teacherName = UserCacheUtil.getUserName(crmCustomer.getTeacherId());

            //新增vip学员es
            CrmModelSaveBO studentModel = new CrmModelSaveBO();
            Map<String, Object> studentMap = BeanUtil.beanToMap(crmStudent);
            studentMap.put("repaymentStatus", contract.getRepaymentStatus());
            studentMap.put("receiveTime",DateUtil.formatDateTime(crmStudent.getReceiveTime()));
            studentMap.put("drawTime",DateUtil.formatDateTime(crmStudent.getDrawTime()));
            studentMap.put("vipDealTime", DateUtil.formatDateTime(contract.getDealTime()));
            studentMap.put("createTime", DateUtil.formatDateTime(crmStudent.getCreateTime()));
            studentMap.put("updateTime", DateUtil.formatDateTime(crmStudent.getUpdateTime()));
            studentMap.put("teacherName", teacherName);
            studentMap.put("ownerUserName", ownerUserName);
            studentModel.setEntity(studentMap);
            savePageByLable(studentModel, crmStudent.getStudentId(), false, CrmEnum.STUDENT.getType());

            //修改合同es
            Map<String, Object> map = new HashMap<>();
            map.put("createUserId", poolChangeUserBO.getOwnerUserId());
            map.put("ownerUserId", poolChangeUserBO.getOwnerUserId());
            map.put("billTime", DateUtils.getTime());
            map.put("updateTime", DateUtils.getTime());
            map.put("ownerOrderPool", null);
            map.put("teacherId", crmCustomer.getTeacherId());
            map.put("teacherName", teacherName);
            map.put("source", crmCustomer.getSource());
            map.put("trainingPeriods", crmCustomer.getTrainingPeriods());
            map.put("studentId", crmStudent.getStudentId());
            map.put("customerId",poolChangeUserBO.getCustomerId());
            map.put("customerName",crmCustomer.getCustomerName());
            map.put("leadsFormTime",DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,crmCustomer.getLeadsFormTime()));
            ElasticUtil.updateField(elasticsearchRestTemplate, map, id, CrmEnum.CONTRACT.getIndex());

            // 变更账单外的合同VIP学员Id
            crmContracts.forEach(otherContract -> {
                Map<String, Object> otherContractMap = new HashMap<>();
                otherContractMap.put("studentId", crmStudent.getStudentId());
                ElasticUtil.updateField(elasticsearchRestTemplate, otherContractMap, otherContract.getContractId(), CrmEnum.CONTRACT.getIndex());

                QueryWrapper<CrmReceivables> wrapper = new QueryWrapper();
                wrapper.eq("contract_id", otherContract.getContractId());
                wrapper.ne("check_status", 7);
                List<CrmReceivables> receivablesByContract = crmReceivablesService.list(wrapper);
                List<Integer> receivablesIds = receivablesByContract.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());

                ElasticUtil.updateField(elasticsearchRestTemplate,"studentId",crmStudent.getStudentId(),receivablesIds, CrmEnum.RECEIVABLES.getIndex());
            });

            //修改回款es
            receivablesList.forEach(crmReceivables -> {
                Map<String, Object> mapReceivables = new HashMap<>();
                mapReceivables.put("createUserId", poolChangeUserBO.getOwnerUserId());
                mapReceivables.put("ownerUserId", poolChangeUserBO.getOwnerUserId());
                mapReceivables.put("updateTime", DateUtils.getTime());
                mapReceivables.put("customerId", poolChangeUserBO.getCustomerId());
                mapReceivables.put("ownerOrderPool", null);
                mapReceivables.put("teacherId", crmCustomer.getTeacherId());
                mapReceivables.put("teacherName", teacherName);
                mapReceivables.put("ownerDeptId", String.valueOf(UserCacheUtil.getUserInfo(poolChangeUserBO.getOwnerUserId()).getDeptId()));
                mapReceivables.put("source", crmCustomer.getSource());
                mapReceivables.put("trainingPeriods", crmCustomer.getTrainingPeriods());
                mapReceivables.put("studentId", crmStudent.getStudentId());
                mapReceivables.put("customerName",crmCustomer.getCustomerName());
                mapReceivables.put("leadsFormTime",DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,crmCustomer.getLeadsFormTime()));
                ElasticUtil.updateField(elasticsearchRestTemplate, mapReceivables, crmReceivables.getReceivablesId(), CrmEnum.RECEIVABLES.getIndex());
            });

            if(poolChangeUserBO.getOwnerUserId() != null){
                addMessage(contract.getName(),ownerUserName,poolChangeUserBO.getOwnerUserId(),AdminMessageEnum.CRM_ORDER_DISTRIBUTION.getType(),contract.getContractId());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            redisCache.unlock(key, value);
        }
    }


    /**
     * 账单恢复领取
     * @param userBO
     */
    @Override
    public void restoreReceive(CrmChangeOwnerUserBO userBO){
        Date expireTime = DateUtils.addDays(new Date(),-expireTimeNum);
        if(CollectionUtil.isNotEmpty(userBO.getIds())){
            for(int i = 0;i < userBO.getIds().size();i++){
                SpringUtils.getBean(ICrmContractService.class).restoreReceiveOrder(userBO.getIds().get(i), expireTime);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restoreReceiveOrder(Integer id, Date expireTime){

        String key = Constants.RESTORE_RECEIVE_ORDER + id;
        String value = UUID.randomUUID().toString();

        //加锁
        boolean b = redisCache.lock(key, value, 10, TimeUnit.SECONDS);
        if (!b) {
            throw new CrmException(CrmCodeEnum.BUSINESS_LOCK_DATA);
        }

        try {

            CrmContract byId = getById(id);
            byId.setOrderPoolStatus(CrmBusinessConstEnum.账单状态_有效.getMsg());
            byId.setExpireTime(expireTime);
            updateById(byId);

            Map<String, Object> map = new HashMap<>();
            map.put("orderPoolStatus", CrmBusinessConstEnum.账单状态_有效.getMsg());
            map.put("expireTime", expireTime);
            ElasticUtil.updateField(elasticsearchRestTemplate, map, id, CrmEnum.CONTRACT.getIndex());

        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            redisCache.unlock(key, value);
        }
    }

    /**
     * 账单置为过期
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void expireOrder(){
        //TODO 修改时间 - 改成配置
        Date expireDate = DateUtils.addDays(new Date(),expireTimeNum);
        List<CrmContract> contractList = baseMapper.queryOrder(expireDate);

        if(CollectionUtil.isNotEmpty(contractList)){

            Date currentDate = new Date();

            contractList.forEach(item -> {
                item.setOrderPoolStatus(CrmBusinessConstEnum.账单状态_过期.getMsg());
                item.setExpireTime(currentDate);
                updateById(item);
            });
            List<Integer> ids = contractList.stream().map(CrmContract::getContractId).collect(Collectors.toList());
            Map<String, Object> updateMap = new HashMap<>();
            updateMap.put("orderPoolStatus", CrmBusinessConstEnum.账单状态_过期.getMsg());
            updateMap.put("expireTime",DateUtil.formatDateTime(currentDate));
            updateField(updateMap, ids);
        }

    }

    /**
     * 根据VIP学员信息查询审核通过合同
     * @param studentId
     * @return
     */
    @Override
    public CrmContract queryContractByStudentId(Integer studentId){
        QueryWrapper<CrmContract> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("check_status", 1);
        queryWrapper.eq("student_id", studentId);
        List<String> categoryList = ListUtil.toList(CrmBusinessConstEnum.账单类别_账单合同.getMsg(),CrmBusinessConstEnum.账单类别_线下合同.getMsg());
        queryWrapper.notIn("contract_category",categoryList);
//        queryWrapper.ne("contract_category", CrmBusinessConstEnum.账单类别_账单合同.getMsg());
        List<CrmContract> crmContracts = baseMapper.selectList(queryWrapper);
        if(CollectionUtil.isNotEmpty(crmContracts)){
            return crmContracts.get(0);
        }
        return null;
    }

    /**
     * 根据学员信息查询审核通过合同
     * @param customerId
     * @return
     */
    @Override
    public List<CrmContract> queryContractDataByCustomerId(Integer customerId){
        QueryWrapper<CrmContract> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("check_status", 1);
        queryWrapper.eq("customer_id", customerId);
        queryWrapper.ne("contract_category", CrmBusinessConstEnum.账单类别_账单合同.getMsg());
        String customerName = crmCustomerService.getCustomerName(customerId);
        List<CrmContract> crmContracts = baseMapper.selectList(queryWrapper);
        for(CrmContract contract : crmContracts){
            contract.setCustomerName(customerName);
            contract.setContractName(contract.getName());
        }
        if(CollectionUtil.isNotEmpty(crmContracts)){
            return crmContracts;
        }
        return null;
    }

}
